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
uart_wait_for_event(QTestState * qts,uint32_t event_addr)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
uart_rw_to_rxd(QTestState * qts,int sock_fd,const char * in,char * out)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
uart_w_to_txd(QTestState * qts,const char * in)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
test_nrf51_uart(void)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
11025657fc6SMarc-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 */
i2c_read_byte(QTestState * qts,uint32_t addr,uint32_t 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
test_microbit_i2c(void)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);
146*58045186SInès Varhol g_assert_cmphex(val, ==, 0x5A);
147b36356f6SStefan Hajnoczi
1487cf19e73SJulia Suvorova val = i2c_read_byte(qts, 0x3A, 0x0D);
149*58045186SInès Varhol g_assert_cmphex(val, ==, 0x5A);
150b36356f6SStefan Hajnoczi
151b36356f6SStefan Hajnoczi /* LSM303 accelerometer detection */
1527cf19e73SJulia Suvorova val = i2c_read_byte(qts, 0x3C, 0x4F);
153*58045186SInès Varhol g_assert_cmphex(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
fill_and_erase(QTestState * qts,hwaddr base,hwaddr size,uint32_t address_reg)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++) {
174*58045186SInès Varhol g_assert_cmphex(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
test_nrf51_nvmc(void)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);
194*58045186SInès Varhol g_assert_cmphex(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
test_nrf51_gpio(void)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;
305*58045186SInès Varhol g_assert_cmphex(actual, ==, 0x01);
3067cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
307*58045186SInès Varhol g_assert_cmphex(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);
312*58045186SInès Varhol g_assert_cmphex(actual, ==, 0x00000000);
3137cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START)
3147cf19e73SJulia Suvorova & 0x01;
315*58045186SInès Varhol g_assert_cmphex(actual, ==, 0x00);
3167cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
317*58045186SInès Varhol g_assert_cmphex(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;
326*58045186SInès Varhol g_assert_cmphex(actual, ==, 0x01);
3277cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
328*58045186SInès Varhol g_assert_cmphex(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;
337*58045186SInès Varhol g_assert_cmphex(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;
340*58045186SInès Varhol g_assert_cmphex(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;
343*58045186SInès Varhol g_assert_cmphex(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;
350*58045186SInès Varhol g_assert_cmphex(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;
353*58045186SInès Varhol g_assert_cmphex(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;
360*58045186SInès Varhol g_assert_cmphex(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;
363*58045186SInès Varhol g_assert_cmphex(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;
379*58045186SInès Varhol g_assert_cmphex(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;
383*58045186SInès Varhol g_assert_cmphex(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
test_nrf51_gpio_detect(void)396a9c9bbeeSChris Laplante static void test_nrf51_gpio_detect(void)
397a9c9bbeeSChris Laplante {
398a9c9bbeeSChris Laplante QTestState *qts = qtest_init("-M microbit");
399a9c9bbeeSChris Laplante int i;
400a9c9bbeeSChris Laplante
401a9c9bbeeSChris Laplante /* Connect input buffer on pins 1-7, configure SENSE for high level */
402a9c9bbeeSChris Laplante for (i = 1; i <= 7; i++) {
403a9c9bbeeSChris Laplante qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START + i * 4,
404a9c9bbeeSChris Laplante deposit32(0, 16, 2, 2));
405a9c9bbeeSChris Laplante }
406a9c9bbeeSChris Laplante
407a9c9bbeeSChris Laplante qtest_irq_intercept_out_named(qts, "/machine/nrf51/gpio", "detect");
408a9c9bbeeSChris Laplante
409a9c9bbeeSChris Laplante for (i = 1; i <= 7; i++) {
410a9c9bbeeSChris Laplante /* Set pin high */
411a9c9bbeeSChris Laplante qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", i, 1);
412a9c9bbeeSChris Laplante uint32_t actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN);
413*58045186SInès Varhol g_assert_cmphex(actual, ==, 1 << i);
414a9c9bbeeSChris Laplante
415a9c9bbeeSChris Laplante /* Check that DETECT is high */
416a9c9bbeeSChris Laplante g_assert_true(qtest_get_irq(qts, 0));
417a9c9bbeeSChris Laplante
418a9c9bbeeSChris Laplante /* Set pin low, check that DETECT goes low. */
419a9c9bbeeSChris Laplante qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", i, 0);
420a9c9bbeeSChris Laplante actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN);
421*58045186SInès Varhol g_assert_cmphex(actual, ==, 0x0);
422a9c9bbeeSChris Laplante g_assert_false(qtest_get_irq(qts, 0));
423a9c9bbeeSChris Laplante }
424a9c9bbeeSChris Laplante
425a9c9bbeeSChris Laplante /* Set pin 0 high, check that DETECT doesn't fire */
426a9c9bbeeSChris Laplante qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
427a9c9bbeeSChris Laplante g_assert_false(qtest_get_irq(qts, 0));
428a9c9bbeeSChris Laplante qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
429a9c9bbeeSChris Laplante
430a9c9bbeeSChris Laplante /* Set pins 1, 2, and 3 high, then set 3 low. Check DETECT is still high */
431a9c9bbeeSChris Laplante for (i = 1; i <= 3; i++) {
432a9c9bbeeSChris Laplante qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", i, 1);
433a9c9bbeeSChris Laplante }
434a9c9bbeeSChris Laplante g_assert_true(qtest_get_irq(qts, 0));
435a9c9bbeeSChris Laplante qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 3, 0);
436a9c9bbeeSChris Laplante g_assert_true(qtest_get_irq(qts, 0));
43781395b6eSDaniel P. Berrangé
43881395b6eSDaniel P. Berrangé qtest_quit(qts);
439a9c9bbeeSChris Laplante }
440a9c9bbeeSChris Laplante
timer_task(QTestState * qts,hwaddr task)4417cf19e73SJulia Suvorova static void timer_task(QTestState *qts, hwaddr task)
4427ec543e4SSteffen Görtz {
4437cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + task, NRF51_TRIGGER_TASK);
4447ec543e4SSteffen Görtz }
4457ec543e4SSteffen Görtz
timer_clear_event(QTestState * qts,hwaddr event)4467cf19e73SJulia Suvorova static void timer_clear_event(QTestState *qts, hwaddr event)
4477ec543e4SSteffen Görtz {
4487cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + event, NRF51_EVENT_CLEAR);
4497ec543e4SSteffen Görtz }
4507ec543e4SSteffen Görtz
timer_set_bitmode(QTestState * qts,uint8_t mode)4517cf19e73SJulia Suvorova static void timer_set_bitmode(QTestState *qts, uint8_t mode)
4527ec543e4SSteffen Görtz {
4537cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_BITMODE, mode);
4547ec543e4SSteffen Görtz }
4557ec543e4SSteffen Görtz
timer_set_prescaler(QTestState * qts,uint8_t prescaler)4567cf19e73SJulia Suvorova static void timer_set_prescaler(QTestState *qts, uint8_t prescaler)
4577ec543e4SSteffen Görtz {
4587cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_PRESCALER, prescaler);
4597ec543e4SSteffen Görtz }
4607ec543e4SSteffen Görtz
timer_set_cc(QTestState * qts,size_t idx,uint32_t value)4617cf19e73SJulia Suvorova static void timer_set_cc(QTestState *qts, size_t idx, uint32_t value)
4627ec543e4SSteffen Görtz {
4637cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_CC0 + idx * 4, value);
4647ec543e4SSteffen Görtz }
4657ec543e4SSteffen Görtz
timer_assert_events(QTestState * qts,uint32_t ev0,uint32_t ev1,uint32_t ev2,uint32_t ev3)4667cf19e73SJulia Suvorova static void timer_assert_events(QTestState *qts, uint32_t ev0, uint32_t ev1,
4677cf19e73SJulia Suvorova uint32_t ev2, uint32_t ev3)
4687ec543e4SSteffen Görtz {
4697cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_0)
4707cf19e73SJulia Suvorova == ev0);
4717cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_1)
4727cf19e73SJulia Suvorova == ev1);
4737cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_2)
4747cf19e73SJulia Suvorova == ev2);
4757cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_3)
4767cf19e73SJulia Suvorova == ev3);
4777ec543e4SSteffen Görtz }
4787ec543e4SSteffen Görtz
test_nrf51_timer(void)4797ec543e4SSteffen Görtz static void test_nrf51_timer(void)
4807ec543e4SSteffen Görtz {
4817ec543e4SSteffen Görtz uint32_t steps_to_overflow = 408;
4827cf19e73SJulia Suvorova QTestState *qts = qtest_init("-M microbit");
4837ec543e4SSteffen Görtz
4847ec543e4SSteffen Görtz /* Compare Match */
4857cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_STOP);
4867cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_CLEAR);
4877ec543e4SSteffen Görtz
4887cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0);
4897cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1);
4907cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2);
4917cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3);
4927ec543e4SSteffen Görtz
4937cf19e73SJulia Suvorova timer_set_bitmode(qts, NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */
4947cf19e73SJulia Suvorova timer_set_prescaler(qts, 0);
4957a21bee2SDaniel P. Berrangé /* Swept over, during the first step */
4967cf19e73SJulia Suvorova timer_set_cc(qts, 0, 2);
4977a21bee2SDaniel P. Berrangé /* Barely miss, after the second step */
4987cf19e73SJulia Suvorova timer_set_cc(qts, 1, 162);
4997a21bee2SDaniel P. Berrangé /* Spot on, after the third step */
5007cf19e73SJulia Suvorova timer_set_cc(qts, 2, 480);
5017ec543e4SSteffen Görtz
5027cf19e73SJulia Suvorova timer_assert_events(qts, 0, 0, 0, 0);
5037ec543e4SSteffen Görtz
5047cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_START);
5057cf19e73SJulia Suvorova qtest_clock_step(qts, 10000);
5067cf19e73SJulia Suvorova timer_assert_events(qts, 1, 0, 0, 0);
5077ec543e4SSteffen Görtz
5087ec543e4SSteffen Görtz /* Swept over on first overflow */
5097cf19e73SJulia Suvorova timer_set_cc(qts, 3, 114);
5107ec543e4SSteffen Görtz
5117cf19e73SJulia Suvorova qtest_clock_step(qts, 10000);
5127cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 0, 0);
5137ec543e4SSteffen Görtz
5147cf19e73SJulia Suvorova qtest_clock_step(qts, 10000);
5157cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 1, 0);
5167ec543e4SSteffen Görtz
5177ec543e4SSteffen Görtz /* Wrap time until internal counter overflows */
5187ec543e4SSteffen Görtz while (steps_to_overflow--) {
5197cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 1, 0);
5207cf19e73SJulia Suvorova qtest_clock_step(qts, 10000);
5217ec543e4SSteffen Görtz }
5227ec543e4SSteffen Görtz
5237cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 1, 1);
5247ec543e4SSteffen Görtz
5257cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0);
5267cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1);
5277cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2);
5287cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3);
5297cf19e73SJulia Suvorova timer_assert_events(qts, 0, 0, 0, 0);
5307ec543e4SSteffen Görtz
5317cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_STOP);
5327ec543e4SSteffen Görtz
5337ec543e4SSteffen Görtz /* Test Proposal: Stop/Shutdown */
5347ec543e4SSteffen Görtz /* Test Proposal: Shortcut Compare -> Clear */
5357ec543e4SSteffen Görtz /* Test Proposal: Shortcut Compare -> Stop */
5367ec543e4SSteffen Görtz /* Test Proposal: Counter Mode */
5377cf19e73SJulia Suvorova
5387cf19e73SJulia Suvorova qtest_quit(qts);
5397ec543e4SSteffen Görtz }
5407ec543e4SSteffen Görtz
main(int argc,char ** argv)54117ff8e18SSteffen Görtz int main(int argc, char **argv)
54217ff8e18SSteffen Görtz {
54317ff8e18SSteffen Görtz g_test_init(&argc, &argv, NULL);
54417ff8e18SSteffen Görtz
54546a6603bSJulia Suvorova qtest_add_func("/microbit/nrf51/uart", test_nrf51_uart);
54617ff8e18SSteffen Görtz qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio);
547a9c9bbeeSChris Laplante qtest_add_func("/microbit/nrf51/gpio_detect", test_nrf51_gpio_detect);
5487743b70fSSteffen Görtz qtest_add_func("/microbit/nrf51/nvmc", test_nrf51_nvmc);
5497ec543e4SSteffen Görtz qtest_add_func("/microbit/nrf51/timer", test_nrf51_timer);
550b36356f6SStefan Hajnoczi qtest_add_func("/microbit/microbit/i2c", test_microbit_i2c);
55117ff8e18SSteffen Görtz
5527cf19e73SJulia Suvorova return g_test_run();
55317ff8e18SSteffen Görtz }
554