1 /*
2 * QTest testcase for STM32L4x5_GPIO
3 *
4 * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5 * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 */
10
11 #include "qemu/osdep.h"
12 #include "libqtest-single.h"
13
14 #define GPIO_BASE_ADDR 0x48000000
15 #define GPIO_SIZE 0x400
16 #define NUM_GPIOS 8
17 #define NUM_GPIO_PINS 16
18
19 #define GPIO_A 0x48000000
20 #define GPIO_B 0x48000400
21 #define GPIO_C 0x48000800
22 #define GPIO_D 0x48000C00
23 #define GPIO_E 0x48001000
24 #define GPIO_F 0x48001400
25 #define GPIO_G 0x48001800
26 #define GPIO_H 0x48001C00
27
28 #define MODER 0x00
29 #define OTYPER 0x04
30 #define PUPDR 0x0C
31 #define IDR 0x10
32 #define ODR 0x14
33 #define BSRR 0x18
34 #define BRR 0x28
35
36 #define MODER_INPUT 0
37 #define MODER_OUTPUT 1
38
39 #define PUPDR_NONE 0
40 #define PUPDR_PULLUP 1
41 #define PUPDR_PULLDOWN 2
42
43 #define OTYPER_PUSH_PULL 0
44 #define OTYPER_OPEN_DRAIN 1
45
46 /* SoC forwards GPIOs to SysCfg */
47 #define SYSCFG "/machine/soc"
48
49 const uint32_t moder_reset[NUM_GPIOS] = {
50 0xABFFFFFF,
51 0xFFFFFEBF,
52 0xFFFFFFFF,
53 0xFFFFFFFF,
54 0xFFFFFFFF,
55 0xFFFFFFFF,
56 0xFFFFFFFF,
57 0x0000000F
58 };
59
60 const uint32_t pupdr_reset[NUM_GPIOS] = {
61 0x64000000,
62 0x00000100,
63 0x00000000,
64 0x00000000,
65 0x00000000,
66 0x00000000,
67 0x00000000,
68 0x00000000
69 };
70
71 const uint32_t idr_reset[NUM_GPIOS] = {
72 0x0000A000,
73 0x00000010,
74 0x00000000,
75 0x00000000,
76 0x00000000,
77 0x00000000,
78 0x00000000,
79 0x00000000
80 };
81
82 #define PIN_MASK 0xF
83 #define GPIO_ADDR_MASK (~(GPIO_SIZE - 1))
84
test_data(uint32_t gpio_addr,uint8_t pin)85 static inline void *test_data(uint32_t gpio_addr, uint8_t pin)
86 {
87 return (void *)(uintptr_t)((gpio_addr & GPIO_ADDR_MASK) | (pin & PIN_MASK));
88 }
89
90 #define test_gpio_addr(data) ((uintptr_t)(data) & GPIO_ADDR_MASK)
91 #define test_pin(data) ((uintptr_t)(data) & PIN_MASK)
92
gpio_readl(unsigned int gpio,unsigned int offset)93 static uint32_t gpio_readl(unsigned int gpio, unsigned int offset)
94 {
95 return readl(gpio + offset);
96 }
97
gpio_writel(unsigned int gpio,unsigned int offset,uint32_t value)98 static void gpio_writel(unsigned int gpio, unsigned int offset, uint32_t value)
99 {
100 writel(gpio + offset, value);
101 }
102
gpio_set_bit(unsigned int gpio,unsigned int reg,unsigned int pin,uint32_t value)103 static void gpio_set_bit(unsigned int gpio, unsigned int reg,
104 unsigned int pin, uint32_t value)
105 {
106 uint32_t mask = 0xFFFFFFFF & ~(0x1 << pin);
107 gpio_writel(gpio, reg, (gpio_readl(gpio, reg) & mask) | value << pin);
108 }
109
gpio_set_2bits(unsigned int gpio,unsigned int reg,unsigned int pin,uint32_t value)110 static void gpio_set_2bits(unsigned int gpio, unsigned int reg,
111 unsigned int pin, uint32_t value)
112 {
113 uint32_t offset = 2 * pin;
114 uint32_t mask = 0xFFFFFFFF & ~(0x3 << offset);
115 gpio_writel(gpio, reg, (gpio_readl(gpio, reg) & mask) | value << offset);
116 }
117
get_gpio_id(uint32_t gpio_addr)118 static unsigned int get_gpio_id(uint32_t gpio_addr)
119 {
120 return (gpio_addr - GPIO_BASE_ADDR) / GPIO_SIZE;
121 }
122
gpio_set_irq(unsigned int gpio,int num,int level)123 static void gpio_set_irq(unsigned int gpio, int num, int level)
124 {
125 g_autofree char *name = g_strdup_printf("/machine/soc/gpio%c",
126 get_gpio_id(gpio) + 'a');
127 qtest_set_irq_in(global_qtest, name, NULL, num, level);
128 }
129
disconnect_all_pins(unsigned int gpio)130 static void disconnect_all_pins(unsigned int gpio)
131 {
132 g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c",
133 get_gpio_id(gpio) + 'a');
134 QDict *r;
135
136 r = qtest_qmp(global_qtest, "{ 'execute': 'qom-set', 'arguments': "
137 "{ 'path': %s, 'property': 'disconnected-pins', 'value': %d } }",
138 path, 0xFFFF);
139 g_assert_false(qdict_haskey(r, "error"));
140 qobject_unref(r);
141 }
142
get_disconnected_pins(unsigned int gpio)143 static uint32_t get_disconnected_pins(unsigned int gpio)
144 {
145 g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c",
146 get_gpio_id(gpio) + 'a');
147 uint32_t disconnected_pins = 0;
148 QDict *r;
149
150 r = qtest_qmp(global_qtest, "{ 'execute': 'qom-get', 'arguments':"
151 " { 'path': %s, 'property': 'disconnected-pins'} }", path);
152 g_assert_false(qdict_haskey(r, "error"));
153 disconnected_pins = qdict_get_int(r, "return");
154 qobject_unref(r);
155 return disconnected_pins;
156 }
157
reset(uint32_t gpio,unsigned int offset)158 static uint32_t reset(uint32_t gpio, unsigned int offset)
159 {
160 switch (offset) {
161 case MODER:
162 return moder_reset[get_gpio_id(gpio)];
163 case PUPDR:
164 return pupdr_reset[get_gpio_id(gpio)];
165 case IDR:
166 return idr_reset[get_gpio_id(gpio)];
167 }
168 return 0x0;
169 }
170
system_reset(void)171 static void system_reset(void)
172 {
173 QDict *r;
174 r = qtest_qmp(global_qtest, "{'execute': 'system_reset'}");
175 g_assert_false(qdict_haskey(r, "error"));
176 qobject_unref(r);
177 }
178
test_idr_reset_value(void)179 static void test_idr_reset_value(void)
180 {
181 /*
182 * Checks that the values in MODER, OTYPER, PUPDR and ODR
183 * after reset are correct, and that the value in IDR is
184 * coherent.
185 * Since AF and analog modes aren't implemented, IDR reset
186 * values aren't the same as with a real board.
187 *
188 * Register IDR contains the actual values of all GPIO pins.
189 * Its value depends on the pins' configuration
190 * (intput/output/analog : register MODER, push-pull/open-drain :
191 * register OTYPER, pull-up/pull-down/none : register PUPDR)
192 * and on the values stored in register ODR
193 * (in case the pin is in output mode).
194 */
195
196 gpio_writel(GPIO_A, MODER, 0xDEADBEEF);
197 gpio_writel(GPIO_A, ODR, 0xDEADBEEF);
198 gpio_writel(GPIO_A, OTYPER, 0xDEADBEEF);
199 gpio_writel(GPIO_A, PUPDR, 0xDEADBEEF);
200
201 gpio_writel(GPIO_B, MODER, 0xDEADBEEF);
202 gpio_writel(GPIO_B, ODR, 0xDEADBEEF);
203 gpio_writel(GPIO_B, OTYPER, 0xDEADBEEF);
204 gpio_writel(GPIO_B, PUPDR, 0xDEADBEEF);
205
206 gpio_writel(GPIO_C, MODER, 0xDEADBEEF);
207 gpio_writel(GPIO_C, ODR, 0xDEADBEEF);
208 gpio_writel(GPIO_C, OTYPER, 0xDEADBEEF);
209 gpio_writel(GPIO_C, PUPDR, 0xDEADBEEF);
210
211 gpio_writel(GPIO_H, MODER, 0xDEADBEEF);
212 gpio_writel(GPIO_H, ODR, 0xDEADBEEF);
213 gpio_writel(GPIO_H, OTYPER, 0xDEADBEEF);
214 gpio_writel(GPIO_H, PUPDR, 0xDEADBEEF);
215
216 system_reset();
217
218 uint32_t moder = gpio_readl(GPIO_A, MODER);
219 uint32_t odr = gpio_readl(GPIO_A, ODR);
220 uint32_t otyper = gpio_readl(GPIO_A, OTYPER);
221 uint32_t pupdr = gpio_readl(GPIO_A, PUPDR);
222 uint32_t idr = gpio_readl(GPIO_A, IDR);
223 /* 15: AF, 14: AF, 13: AF, 12: Analog ... */
224 /* here AF is the same as Analog and Input mode */
225 g_assert_cmphex(moder, ==, reset(GPIO_A, MODER));
226 g_assert_cmphex(odr, ==, reset(GPIO_A, ODR));
227 g_assert_cmphex(otyper, ==, reset(GPIO_A, OTYPER));
228 /* 15: pull-up, 14: pull-down, 13: pull-up, 12: neither ... */
229 g_assert_cmphex(pupdr, ==, reset(GPIO_A, PUPDR));
230 /* 15 : 1, 14: 0, 13: 1, 12 : reset value ... */
231 g_assert_cmphex(idr, ==, reset(GPIO_A, IDR));
232
233 moder = gpio_readl(GPIO_B, MODER);
234 odr = gpio_readl(GPIO_B, ODR);
235 otyper = gpio_readl(GPIO_B, OTYPER);
236 pupdr = gpio_readl(GPIO_B, PUPDR);
237 idr = gpio_readl(GPIO_B, IDR);
238 /* ... 5: Analog, 4: AF, 3: AF, 2: Analog ... */
239 /* here AF is the same as Analog and Input mode */
240 g_assert_cmphex(moder, ==, reset(GPIO_B, MODER));
241 g_assert_cmphex(odr, ==, reset(GPIO_B, ODR));
242 g_assert_cmphex(otyper, ==, reset(GPIO_B, OTYPER));
243 /* ... 5: neither, 4: pull-up, 3: neither ... */
244 g_assert_cmphex(pupdr, ==, reset(GPIO_B, PUPDR));
245 /* ... 5 : reset value, 4 : 1, 3 : reset value ... */
246 g_assert_cmphex(idr, ==, reset(GPIO_B, IDR));
247
248 moder = gpio_readl(GPIO_C, MODER);
249 odr = gpio_readl(GPIO_C, ODR);
250 otyper = gpio_readl(GPIO_C, OTYPER);
251 pupdr = gpio_readl(GPIO_C, PUPDR);
252 idr = gpio_readl(GPIO_C, IDR);
253 /* Analog, same as Input mode*/
254 g_assert_cmphex(moder, ==, reset(GPIO_C, MODER));
255 g_assert_cmphex(odr, ==, reset(GPIO_C, ODR));
256 g_assert_cmphex(otyper, ==, reset(GPIO_C, OTYPER));
257 /* no pull-up or pull-down */
258 g_assert_cmphex(pupdr, ==, reset(GPIO_C, PUPDR));
259 /* reset value */
260 g_assert_cmphex(idr, ==, reset(GPIO_C, IDR));
261
262 moder = gpio_readl(GPIO_H, MODER);
263 odr = gpio_readl(GPIO_H, ODR);
264 otyper = gpio_readl(GPIO_H, OTYPER);
265 pupdr = gpio_readl(GPIO_H, PUPDR);
266 idr = gpio_readl(GPIO_H, IDR);
267 /* Analog, same as Input mode */
268 g_assert_cmphex(moder, ==, reset(GPIO_H, MODER));
269 g_assert_cmphex(odr, ==, reset(GPIO_H, ODR));
270 g_assert_cmphex(otyper, ==, reset(GPIO_H, OTYPER));
271 /* no pull-up or pull-down */
272 g_assert_cmphex(pupdr, ==, reset(GPIO_H, PUPDR));
273 /* reset value */
274 g_assert_cmphex(idr, ==, reset(GPIO_H, IDR));
275 }
276
test_gpio_output_mode(const void * data)277 static void test_gpio_output_mode(const void *data)
278 {
279 /*
280 * Checks that setting a bit in ODR sets the corresponding
281 * GPIO line high : it should set the right bit in IDR
282 * and send an irq to syscfg.
283 * Additionally, it checks that values written to ODR
284 * when not in output mode are stored and not discarded.
285 */
286 unsigned int pin = test_pin(data);
287 uint32_t gpio = test_gpio_addr(data);
288 unsigned int gpio_id = get_gpio_id(gpio);
289
290 qtest_irq_intercept_in(global_qtest, SYSCFG);
291
292 /* Set a bit in ODR and check nothing happens */
293 gpio_set_bit(gpio, ODR, pin, 1);
294 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
295 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
296
297 /* Configure the relevant line as output and check the pin is high */
298 gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
299 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
300 g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
301
302 /* Reset the bit in ODR and check the pin is low */
303 gpio_set_bit(gpio, ODR, pin, 0);
304 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
305 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
306
307 /* Clean the test */
308 gpio_writel(gpio, ODR, reset(gpio, ODR));
309 gpio_writel(gpio, MODER, reset(gpio, MODER));
310 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
311 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
312 }
313
test_gpio_input_mode(const void * data)314 static void test_gpio_input_mode(const void *data)
315 {
316 /*
317 * Test that setting a line high/low externally sets the
318 * corresponding GPIO line high/low : it should set the
319 * right bit in IDR and send an irq to syscfg.
320 */
321 unsigned int pin = test_pin(data);
322 uint32_t gpio = test_gpio_addr(data);
323 unsigned int gpio_id = get_gpio_id(gpio);
324
325 qtest_irq_intercept_in(global_qtest, SYSCFG);
326
327 /* Configure a line as input, raise it, and check that the pin is high */
328 gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
329 gpio_set_irq(gpio, pin, 1);
330 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
331 g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
332
333 /* Lower the line and check that the pin is low */
334 gpio_set_irq(gpio, pin, 0);
335 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
336 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
337
338 /* Clean the test */
339 gpio_writel(gpio, MODER, reset(gpio, MODER));
340 disconnect_all_pins(gpio);
341 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
342 }
343
test_pull_up_pull_down(const void * data)344 static void test_pull_up_pull_down(const void *data)
345 {
346 /*
347 * Test that a floating pin with pull-up sets the pin
348 * high and vice-versa.
349 */
350 unsigned int pin = test_pin(data);
351 uint32_t gpio = test_gpio_addr(data);
352 unsigned int gpio_id = get_gpio_id(gpio);
353
354 qtest_irq_intercept_in(global_qtest, SYSCFG);
355
356 /* Configure a line as input with pull-up, check the line is set high */
357 gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
358 gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLUP);
359 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
360 g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
361
362 /* Configure the line with pull-down, check the line is low */
363 gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLDOWN);
364 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
365 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
366
367 /* Clean the test */
368 gpio_writel(gpio, MODER, reset(gpio, MODER));
369 gpio_writel(gpio, PUPDR, reset(gpio, PUPDR));
370 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
371 }
372
test_push_pull(const void * data)373 static void test_push_pull(const void *data)
374 {
375 /*
376 * Test that configuring a line in push-pull output mode
377 * disconnects the pin, that the pin can't be set or reset
378 * externally afterwards.
379 */
380 unsigned int pin = test_pin(data);
381 uint32_t gpio = test_gpio_addr(data);
382 uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
383
384 qtest_irq_intercept_in(global_qtest, SYSCFG);
385
386 /* Setting a line high externally, configuring it in push-pull output */
387 /* And checking the pin was disconnected */
388 gpio_set_irq(gpio, pin, 1);
389 gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
390 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
391 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
392
393 /* Setting a line low externally, configuring it in push-pull output */
394 /* And checking the pin was disconnected */
395 gpio_set_irq(gpio2, pin, 0);
396 gpio_set_bit(gpio2, ODR, pin, 1);
397 gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
398 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
399 g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
400
401 /* Trying to set a push-pull output pin, checking it doesn't work */
402 gpio_set_irq(gpio, pin, 1);
403 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
404 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
405
406 /* Trying to reset a push-pull output pin, checking it doesn't work */
407 gpio_set_irq(gpio2, pin, 0);
408 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
409 g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
410
411 /* Clean the test */
412 gpio_writel(gpio, MODER, reset(gpio, MODER));
413 gpio_writel(gpio2, ODR, reset(gpio2, ODR));
414 gpio_writel(gpio2, MODER, reset(gpio2, MODER));
415 }
416
test_open_drain(const void * data)417 static void test_open_drain(const void *data)
418 {
419 /*
420 * Test that configuring a line in open-drain output mode
421 * disconnects a pin set high externally and that the pin
422 * can't be set high externally while configured in open-drain.
423 *
424 * However a pin set low externally shouldn't be disconnected,
425 * and it can be set low externally when in open-drain mode.
426 */
427 unsigned int pin = test_pin(data);
428 uint32_t gpio = test_gpio_addr(data);
429 uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
430
431 qtest_irq_intercept_in(global_qtest, SYSCFG);
432
433 /* Setting a line high externally, configuring it in open-drain output */
434 /* And checking the pin was disconnected */
435 gpio_set_irq(gpio, pin, 1);
436 gpio_set_bit(gpio, OTYPER, pin, OTYPER_OPEN_DRAIN);
437 gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
438 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
439 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
440
441 /* Setting a line low externally, configuring it in open-drain output */
442 /* And checking the pin wasn't disconnected */
443 gpio_set_irq(gpio2, pin, 0);
444 gpio_set_bit(gpio2, ODR, pin, 1);
445 gpio_set_bit(gpio2, OTYPER, pin, OTYPER_OPEN_DRAIN);
446 gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
447 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
448 g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
449 reset(gpio2, IDR) & ~(1 << pin));
450
451 /* Trying to set a open-drain output pin, checking it doesn't work */
452 gpio_set_irq(gpio, pin, 1);
453 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
454 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
455
456 /* Trying to reset a open-drain output pin, checking it works */
457 gpio_set_bit(gpio, ODR, pin, 1);
458 gpio_set_irq(gpio, pin, 0);
459 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
460 g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
461 reset(gpio2, IDR) & ~(1 << pin));
462
463 /* Clean the test */
464 disconnect_all_pins(gpio2);
465 gpio_writel(gpio2, OTYPER, reset(gpio2, OTYPER));
466 gpio_writel(gpio2, ODR, reset(gpio2, ODR));
467 gpio_writel(gpio2, MODER, reset(gpio2, MODER));
468 g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR));
469 disconnect_all_pins(gpio);
470 gpio_writel(gpio, OTYPER, reset(gpio, OTYPER));
471 gpio_writel(gpio, ODR, reset(gpio, ODR));
472 gpio_writel(gpio, MODER, reset(gpio, MODER));
473 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
474 }
475
test_bsrr_brr(const void * data)476 static void test_bsrr_brr(const void *data)
477 {
478 /*
479 * Test that writing a '1' in BSS and BSRR
480 * has the desired effect on ODR.
481 * In BSRR, BSx has priority over BRx.
482 */
483 unsigned int pin = test_pin(data);
484 uint32_t gpio = test_gpio_addr(data);
485
486 gpio_writel(gpio, BSRR, (1 << pin));
487 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
488
489 gpio_writel(gpio, BSRR, (1 << (pin + NUM_GPIO_PINS)));
490 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
491
492 gpio_writel(gpio, BSRR, (1 << pin));
493 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
494
495 gpio_writel(gpio, BRR, (1 << pin));
496 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
497
498 /* BSx should have priority over BRx */
499 gpio_writel(gpio, BSRR, (1 << pin) | (1 << (pin + NUM_GPIO_PINS)));
500 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
501
502 gpio_writel(gpio, BRR, (1 << pin));
503 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
504
505 gpio_writel(gpio, ODR, reset(gpio, ODR));
506 }
507
main(int argc,char ** argv)508 int main(int argc, char **argv)
509 {
510 int ret;
511
512 g_test_init(&argc, &argv, NULL);
513 g_test_set_nonfatal_assertions();
514 qtest_add_func("stm32l4x5/gpio/test_idr_reset_value",
515 test_idr_reset_value);
516 /*
517 * The inputs for the tests (gpio and pin) can be changed,
518 * but the tests don't work for pins that are high at reset
519 * (GPIOA15, GPIO13 and GPIOB5).
520 * Specifically, rising the pin then checking `get_irq()`
521 * is problematic since the pin was already high.
522 */
523 qtest_add_data_func("stm32l4x5/gpio/test_gpioc5_output_mode",
524 test_data(GPIO_C, 5),
525 test_gpio_output_mode);
526 qtest_add_data_func("stm32l4x5/gpio/test_gpioh3_output_mode",
527 test_data(GPIO_H, 3),
528 test_gpio_output_mode);
529 qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode1",
530 test_data(GPIO_D, 6),
531 test_gpio_input_mode);
532 qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode2",
533 test_data(GPIO_C, 10),
534 test_gpio_input_mode);
535 qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down1",
536 test_data(GPIO_B, 5),
537 test_pull_up_pull_down);
538 qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down2",
539 test_data(GPIO_F, 1),
540 test_pull_up_pull_down);
541 qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull1",
542 test_data(GPIO_G, 6),
543 test_push_pull);
544 qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull2",
545 test_data(GPIO_H, 3),
546 test_push_pull);
547 qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain1",
548 test_data(GPIO_C, 4),
549 test_open_drain);
550 qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain2",
551 test_data(GPIO_E, 11),
552 test_open_drain);
553 qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr1",
554 test_data(GPIO_A, 12),
555 test_bsrr_brr);
556 qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr2",
557 test_data(GPIO_D, 0),
558 test_bsrr_brr);
559
560 qtest_start("-machine b-l475e-iot01a");
561 ret = g_test_run();
562 qtest_end();
563
564 return ret;
565 }
566