xref: /qemu/tests/qtest/microbit-test.c (revision 25657fc6c1b693096e2ceadaa53cd10c1e81c8d9)
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