]>
Commit | Line | Data |
---|---|---|
17ff8e18 SG |
1 | /* |
2 | * QTest testcase for Microbit board using the Nordic Semiconductor nRF51 SoC. | |
3 | * | |
4 | * nRF51: | |
5 | * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf | |
6 | * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf | |
7 | * | |
8 | * Microbit Board: http://microbit.org/ | |
9 | * | |
10 | * Copyright 2018 Steffen Görtz <[email protected]> | |
11 | * | |
12 | * This code is licensed under the GPL version 2 or later. See | |
13 | * the COPYING file in the top-level directory. | |
14 | */ | |
15 | ||
16 | ||
17 | #include "qemu/osdep.h" | |
18 | #include "exec/hwaddr.h" | |
19 | #include "libqtest.h" | |
20 | ||
21 | #include "hw/arm/nrf51.h" | |
22 | #include "hw/gpio/nrf51_gpio.h" | |
23 | ||
24 | static void test_nrf51_gpio(void) | |
25 | { | |
26 | size_t i; | |
27 | uint32_t actual, expected; | |
28 | ||
29 | struct { | |
30 | hwaddr addr; | |
31 | uint32_t expected; | |
32 | } const reset_state[] = { | |
33 | {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000}, | |
34 | {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000}, | |
35 | {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000}, | |
36 | {NRF51_GPIO_REG_DIRCLR, 0x00000000} | |
37 | }; | |
38 | ||
39 | /* Check reset state */ | |
40 | for (i = 0; i < ARRAY_SIZE(reset_state); i++) { | |
41 | expected = reset_state[i].expected; | |
42 | actual = readl(NRF51_GPIO_BASE + reset_state[i].addr); | |
43 | g_assert_cmpuint(actual, ==, expected); | |
44 | } | |
45 | ||
46 | for (i = 0; i < NRF51_GPIO_PINS; i++) { | |
47 | expected = 0x00000002; | |
48 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START + i * 4); | |
49 | g_assert_cmpuint(actual, ==, expected); | |
50 | } | |
51 | ||
52 | /* Check dir bit consistency between dir and cnf */ | |
53 | /* Check set via DIRSET */ | |
54 | expected = 0x80000001; | |
55 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected); | |
56 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); | |
57 | g_assert_cmpuint(actual, ==, expected); | |
58 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01; | |
59 | g_assert_cmpuint(actual, ==, 0x01); | |
60 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; | |
61 | g_assert_cmpuint(actual, ==, 0x01); | |
62 | ||
63 | /* Check clear via DIRCLR */ | |
64 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001); | |
65 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); | |
66 | g_assert_cmpuint(actual, ==, 0x00000000); | |
67 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01; | |
68 | g_assert_cmpuint(actual, ==, 0x00); | |
69 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; | |
70 | g_assert_cmpuint(actual, ==, 0x00); | |
71 | ||
72 | /* Check set via DIR */ | |
73 | expected = 0x80000001; | |
74 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected); | |
75 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); | |
76 | g_assert_cmpuint(actual, ==, expected); | |
77 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01; | |
78 | g_assert_cmpuint(actual, ==, 0x01); | |
79 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; | |
80 | g_assert_cmpuint(actual, ==, 0x01); | |
81 | ||
82 | /* Reset DIR */ | |
83 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000); | |
84 | ||
85 | /* Check Input propagates */ | |
86 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00); | |
87 | qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0); | |
88 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
89 | g_assert_cmpuint(actual, ==, 0x00); | |
90 | qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1); | |
91 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
92 | g_assert_cmpuint(actual, ==, 0x01); | |
93 | qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1); | |
94 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
95 | g_assert_cmpuint(actual, ==, 0x01); | |
96 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); | |
97 | ||
98 | /* Check pull-up working */ | |
99 | qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0); | |
100 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000); | |
101 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
102 | g_assert_cmpuint(actual, ==, 0x00); | |
103 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110); | |
104 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
105 | g_assert_cmpuint(actual, ==, 0x01); | |
106 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); | |
107 | ||
108 | /* Check pull-down working */ | |
109 | qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1); | |
110 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000); | |
111 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
112 | g_assert_cmpuint(actual, ==, 0x01); | |
113 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110); | |
114 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
115 | g_assert_cmpuint(actual, ==, 0x00); | |
116 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); | |
117 | qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1); | |
118 | ||
119 | /* Check Output propagates */ | |
120 | irq_intercept_out("/machine/nrf51"); | |
121 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011); | |
122 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); | |
123 | g_assert_true(get_irq(0)); | |
124 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01); | |
125 | g_assert_false(get_irq(0)); | |
126 | ||
127 | /* Check self-stimulation */ | |
128 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01); | |
129 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); | |
130 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
131 | g_assert_cmpuint(actual, ==, 0x01); | |
132 | ||
133 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01); | |
134 | actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; | |
135 | g_assert_cmpuint(actual, ==, 0x00); | |
136 | ||
137 | /* | |
138 | * Check short-circuit - generates an guest_error which must be checked | |
139 | * manually as long as qtest can not scan qemu_log messages | |
140 | */ | |
141 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01); | |
142 | writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); | |
143 | qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0); | |
144 | } | |
145 | ||
146 | int main(int argc, char **argv) | |
147 | { | |
148 | int ret; | |
149 | ||
150 | g_test_init(&argc, &argv, NULL); | |
151 | ||
152 | global_qtest = qtest_initf("-machine microbit"); | |
153 | ||
154 | qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio); | |
155 | ||
156 | ret = g_test_run(); | |
157 | ||
158 | qtest_quit(global_qtest); | |
159 | return ret; | |
160 | } |