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