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
test_idr_reset_value(void)172 static void test_idr_reset_value(void)
173 {
174 /*
175 * Checks that the values in MODER, OTYPER, PUPDR and ODR
176 * after reset are correct, and that the value in IDR is
177 * coherent.
178 * Since AF and analog modes aren't implemented, IDR reset
179 * values aren't the same as with a real board.
180 *
181 * Register IDR contains the actual values of all GPIO pins.
182 * Its value depends on the pins' configuration
183 * (intput/output/analog : register MODER, push-pull/open-drain :
184 * register OTYPER, pull-up/pull-down/none : register PUPDR)
185 * and on the values stored in register ODR
186 * (in case the pin is in output mode).
187 */
188
189 gpio_writel(GPIO_A, MODER, 0xDEADBEEF);
190 gpio_writel(GPIO_A, ODR, 0xDEADBEEF);
191 gpio_writel(GPIO_A, OTYPER, 0xDEADBEEF);
192 gpio_writel(GPIO_A, PUPDR, 0xDEADBEEF);
193
194 gpio_writel(GPIO_B, MODER, 0xDEADBEEF);
195 gpio_writel(GPIO_B, ODR, 0xDEADBEEF);
196 gpio_writel(GPIO_B, OTYPER, 0xDEADBEEF);
197 gpio_writel(GPIO_B, PUPDR, 0xDEADBEEF);
198
199 gpio_writel(GPIO_C, MODER, 0xDEADBEEF);
200 gpio_writel(GPIO_C, ODR, 0xDEADBEEF);
201 gpio_writel(GPIO_C, OTYPER, 0xDEADBEEF);
202 gpio_writel(GPIO_C, PUPDR, 0xDEADBEEF);
203
204 gpio_writel(GPIO_H, MODER, 0xDEADBEEF);
205 gpio_writel(GPIO_H, ODR, 0xDEADBEEF);
206 gpio_writel(GPIO_H, OTYPER, 0xDEADBEEF);
207 gpio_writel(GPIO_H, PUPDR, 0xDEADBEEF);
208
209 qtest_system_reset(global_qtest);
210
211 uint32_t moder = gpio_readl(GPIO_A, MODER);
212 uint32_t odr = gpio_readl(GPIO_A, ODR);
213 uint32_t otyper = gpio_readl(GPIO_A, OTYPER);
214 uint32_t pupdr = gpio_readl(GPIO_A, PUPDR);
215 uint32_t idr = gpio_readl(GPIO_A, IDR);
216 /* 15: AF, 14: AF, 13: AF, 12: Analog ... */
217 /* here AF is the same as Analog and Input mode */
218 g_assert_cmphex(moder, ==, reset(GPIO_A, MODER));
219 g_assert_cmphex(odr, ==, reset(GPIO_A, ODR));
220 g_assert_cmphex(otyper, ==, reset(GPIO_A, OTYPER));
221 /* 15: pull-up, 14: pull-down, 13: pull-up, 12: neither ... */
222 g_assert_cmphex(pupdr, ==, reset(GPIO_A, PUPDR));
223 /* 15 : 1, 14: 0, 13: 1, 12 : reset value ... */
224 g_assert_cmphex(idr, ==, reset(GPIO_A, IDR));
225
226 moder = gpio_readl(GPIO_B, MODER);
227 odr = gpio_readl(GPIO_B, ODR);
228 otyper = gpio_readl(GPIO_B, OTYPER);
229 pupdr = gpio_readl(GPIO_B, PUPDR);
230 idr = gpio_readl(GPIO_B, IDR);
231 /* ... 5: Analog, 4: AF, 3: AF, 2: Analog ... */
232 /* here AF is the same as Analog and Input mode */
233 g_assert_cmphex(moder, ==, reset(GPIO_B, MODER));
234 g_assert_cmphex(odr, ==, reset(GPIO_B, ODR));
235 g_assert_cmphex(otyper, ==, reset(GPIO_B, OTYPER));
236 /* ... 5: neither, 4: pull-up, 3: neither ... */
237 g_assert_cmphex(pupdr, ==, reset(GPIO_B, PUPDR));
238 /* ... 5 : reset value, 4 : 1, 3 : reset value ... */
239 g_assert_cmphex(idr, ==, reset(GPIO_B, IDR));
240
241 moder = gpio_readl(GPIO_C, MODER);
242 odr = gpio_readl(GPIO_C, ODR);
243 otyper = gpio_readl(GPIO_C, OTYPER);
244 pupdr = gpio_readl(GPIO_C, PUPDR);
245 idr = gpio_readl(GPIO_C, IDR);
246 /* Analog, same as Input mode*/
247 g_assert_cmphex(moder, ==, reset(GPIO_C, MODER));
248 g_assert_cmphex(odr, ==, reset(GPIO_C, ODR));
249 g_assert_cmphex(otyper, ==, reset(GPIO_C, OTYPER));
250 /* no pull-up or pull-down */
251 g_assert_cmphex(pupdr, ==, reset(GPIO_C, PUPDR));
252 /* reset value */
253 g_assert_cmphex(idr, ==, reset(GPIO_C, IDR));
254
255 moder = gpio_readl(GPIO_H, MODER);
256 odr = gpio_readl(GPIO_H, ODR);
257 otyper = gpio_readl(GPIO_H, OTYPER);
258 pupdr = gpio_readl(GPIO_H, PUPDR);
259 idr = gpio_readl(GPIO_H, IDR);
260 /* Analog, same as Input mode */
261 g_assert_cmphex(moder, ==, reset(GPIO_H, MODER));
262 g_assert_cmphex(odr, ==, reset(GPIO_H, ODR));
263 g_assert_cmphex(otyper, ==, reset(GPIO_H, OTYPER));
264 /* no pull-up or pull-down */
265 g_assert_cmphex(pupdr, ==, reset(GPIO_H, PUPDR));
266 /* reset value */
267 g_assert_cmphex(idr, ==, reset(GPIO_H, IDR));
268 }
269
test_gpio_output_mode(const void * data)270 static void test_gpio_output_mode(const void *data)
271 {
272 /*
273 * Checks that setting a bit in ODR sets the corresponding
274 * GPIO line high : it should set the right bit in IDR
275 * and send an irq to syscfg.
276 * Additionally, it checks that values written to ODR
277 * when not in output mode are stored and not discarded.
278 */
279 unsigned int pin = test_pin(data);
280 uint32_t gpio = test_gpio_addr(data);
281 unsigned int gpio_id = get_gpio_id(gpio);
282
283 qtest_irq_intercept_in(global_qtest, SYSCFG);
284
285 /* Set a bit in ODR and check nothing happens */
286 gpio_set_bit(gpio, ODR, pin, 1);
287 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
288 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
289
290 /* Configure the relevant line as output and check the pin is high */
291 gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
292 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
293 g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
294
295 /* Reset the bit in ODR and check the pin is low */
296 gpio_set_bit(gpio, ODR, pin, 0);
297 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
298 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
299
300 /* Clean the test */
301 gpio_writel(gpio, ODR, reset(gpio, ODR));
302 gpio_writel(gpio, MODER, reset(gpio, MODER));
303 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
304 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
305 }
306
test_gpio_input_mode(const void * data)307 static void test_gpio_input_mode(const void *data)
308 {
309 /*
310 * Test that setting a line high/low externally sets the
311 * corresponding GPIO line high/low : it should set the
312 * right bit in IDR and send an irq to syscfg.
313 */
314 unsigned int pin = test_pin(data);
315 uint32_t gpio = test_gpio_addr(data);
316 unsigned int gpio_id = get_gpio_id(gpio);
317
318 qtest_irq_intercept_in(global_qtest, SYSCFG);
319
320 /* Configure a line as input, raise it, and check that the pin is high */
321 gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
322 gpio_set_irq(gpio, pin, 1);
323 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
324 g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
325
326 /* Lower the line and check that the pin is low */
327 gpio_set_irq(gpio, pin, 0);
328 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
329 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
330
331 /* Clean the test */
332 gpio_writel(gpio, MODER, reset(gpio, MODER));
333 disconnect_all_pins(gpio);
334 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
335 }
336
test_pull_up_pull_down(const void * data)337 static void test_pull_up_pull_down(const void *data)
338 {
339 /*
340 * Test that a floating pin with pull-up sets the pin
341 * high and vice-versa.
342 */
343 unsigned int pin = test_pin(data);
344 uint32_t gpio = test_gpio_addr(data);
345 unsigned int gpio_id = get_gpio_id(gpio);
346
347 qtest_irq_intercept_in(global_qtest, SYSCFG);
348
349 /* Configure a line as input with pull-up, check the line is set high */
350 gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
351 gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLUP);
352 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
353 g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
354
355 /* Configure the line with pull-down, check the line is low */
356 gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLDOWN);
357 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
358 g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
359
360 /* Clean the test */
361 gpio_writel(gpio, MODER, reset(gpio, MODER));
362 gpio_writel(gpio, PUPDR, reset(gpio, PUPDR));
363 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
364 }
365
test_push_pull(const void * data)366 static void test_push_pull(const void *data)
367 {
368 /*
369 * Test that configuring a line in push-pull output mode
370 * disconnects the pin, that the pin can't be set or reset
371 * externally afterwards.
372 */
373 unsigned int pin = test_pin(data);
374 uint32_t gpio = test_gpio_addr(data);
375 uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
376
377 qtest_irq_intercept_in(global_qtest, SYSCFG);
378
379 /* Setting a line high externally, configuring it in push-pull output */
380 /* And checking the pin was disconnected */
381 gpio_set_irq(gpio, pin, 1);
382 gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
383 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
384 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
385
386 /* Setting a line low externally, configuring it in push-pull output */
387 /* And checking the pin was disconnected */
388 gpio_set_irq(gpio2, pin, 0);
389 gpio_set_bit(gpio2, ODR, pin, 1);
390 gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
391 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
392 g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
393
394 /* Trying to set a push-pull output pin, checking it doesn't work */
395 gpio_set_irq(gpio, pin, 1);
396 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
397 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
398
399 /* Trying to reset a push-pull output pin, checking it doesn't work */
400 gpio_set_irq(gpio2, pin, 0);
401 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
402 g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
403
404 /* Clean the test */
405 gpio_writel(gpio, MODER, reset(gpio, MODER));
406 gpio_writel(gpio2, ODR, reset(gpio2, ODR));
407 gpio_writel(gpio2, MODER, reset(gpio2, MODER));
408 }
409
test_open_drain(const void * data)410 static void test_open_drain(const void *data)
411 {
412 /*
413 * Test that configuring a line in open-drain output mode
414 * disconnects a pin set high externally and that the pin
415 * can't be set high externally while configured in open-drain.
416 *
417 * However a pin set low externally shouldn't be disconnected,
418 * and it can be set low externally when in open-drain mode.
419 */
420 unsigned int pin = test_pin(data);
421 uint32_t gpio = test_gpio_addr(data);
422 uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
423
424 qtest_irq_intercept_in(global_qtest, SYSCFG);
425
426 /* Setting a line high externally, configuring it in open-drain output */
427 /* And checking the pin was disconnected */
428 gpio_set_irq(gpio, pin, 1);
429 gpio_set_bit(gpio, OTYPER, pin, OTYPER_OPEN_DRAIN);
430 gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
431 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
432 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
433
434 /* Setting a line low externally, configuring it in open-drain output */
435 /* And checking the pin wasn't disconnected */
436 gpio_set_irq(gpio2, pin, 0);
437 gpio_set_bit(gpio2, ODR, pin, 1);
438 gpio_set_bit(gpio2, OTYPER, pin, OTYPER_OPEN_DRAIN);
439 gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
440 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
441 g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
442 reset(gpio2, IDR) & ~(1 << pin));
443
444 /* Trying to set a open-drain output pin, checking it doesn't work */
445 gpio_set_irq(gpio, pin, 1);
446 g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
447 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
448
449 /* Trying to reset a open-drain output pin, checking it works */
450 gpio_set_bit(gpio, ODR, pin, 1);
451 gpio_set_irq(gpio, pin, 0);
452 g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
453 g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
454 reset(gpio2, IDR) & ~(1 << pin));
455
456 /* Clean the test */
457 disconnect_all_pins(gpio2);
458 gpio_writel(gpio2, OTYPER, reset(gpio2, OTYPER));
459 gpio_writel(gpio2, ODR, reset(gpio2, ODR));
460 gpio_writel(gpio2, MODER, reset(gpio2, MODER));
461 g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR));
462 disconnect_all_pins(gpio);
463 gpio_writel(gpio, OTYPER, reset(gpio, OTYPER));
464 gpio_writel(gpio, ODR, reset(gpio, ODR));
465 gpio_writel(gpio, MODER, reset(gpio, MODER));
466 g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
467 }
468
test_bsrr_brr(const void * data)469 static void test_bsrr_brr(const void *data)
470 {
471 /*
472 * Test that writing a '1' in BSS and BSRR
473 * has the desired effect on ODR.
474 * In BSRR, BSx has priority over BRx.
475 */
476 unsigned int pin = test_pin(data);
477 uint32_t gpio = test_gpio_addr(data);
478
479 gpio_writel(gpio, BSRR, (1 << pin));
480 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
481
482 gpio_writel(gpio, BSRR, (1 << (pin + NUM_GPIO_PINS)));
483 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
484
485 gpio_writel(gpio, BSRR, (1 << pin));
486 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
487
488 gpio_writel(gpio, BRR, (1 << pin));
489 g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
490
491 /* BSx should have priority over BRx */
492 gpio_writel(gpio, BSRR, (1 << pin) | (1 << (pin + NUM_GPIO_PINS)));
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 gpio_writel(gpio, ODR, reset(gpio, ODR));
499 }
500
test_clock_enable(void)501 static void test_clock_enable(void)
502 {
503 /*
504 * For each GPIO, enable its clock in RCC
505 * and check that its clock period changes to SYSCLK_PERIOD
506 */
507 unsigned int gpio_id;
508
509 for (uint32_t gpio = GPIO_A; gpio <= GPIO_H; gpio += GPIO_B - GPIO_A) {
510 gpio_id = get_gpio_id(gpio);
511 g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c/clk",
512 gpio_id + 'a');
513 g_assert_cmpuint(get_clock_period(global_qtest, path), ==, 0);
514 /* Enable the gpio clock */
515 writel(RCC_AHB2ENR, readl(RCC_AHB2ENR) | (0x1 << gpio_id));
516 g_assert_cmpuint(get_clock_period(global_qtest, path), ==,
517 SYSCLK_PERIOD);
518 }
519 }
520
main(int argc,char ** argv)521 int main(int argc, char **argv)
522 {
523 int ret;
524
525 g_test_init(&argc, &argv, NULL);
526 g_test_set_nonfatal_assertions();
527 qtest_add_func("stm32l4x5/gpio/test_idr_reset_value",
528 test_idr_reset_value);
529 /*
530 * The inputs for the tests (gpio and pin) can be changed,
531 * but the tests don't work for pins that are high at reset
532 * (GPIOA15, GPIO13 and GPIOB5).
533 * Specifically, rising the pin then checking `get_irq()`
534 * is problematic since the pin was already high.
535 */
536 qtest_add_data_func("stm32l4x5/gpio/test_gpioc5_output_mode",
537 test_data(GPIO_C, 5),
538 test_gpio_output_mode);
539 qtest_add_data_func("stm32l4x5/gpio/test_gpioh3_output_mode",
540 test_data(GPIO_H, 3),
541 test_gpio_output_mode);
542 qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode1",
543 test_data(GPIO_D, 6),
544 test_gpio_input_mode);
545 qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode2",
546 test_data(GPIO_C, 10),
547 test_gpio_input_mode);
548 qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down1",
549 test_data(GPIO_B, 5),
550 test_pull_up_pull_down);
551 qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down2",
552 test_data(GPIO_F, 1),
553 test_pull_up_pull_down);
554 qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull1",
555 test_data(GPIO_G, 6),
556 test_push_pull);
557 qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull2",
558 test_data(GPIO_H, 3),
559 test_push_pull);
560 qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain1",
561 test_data(GPIO_C, 4),
562 test_open_drain);
563 qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain2",
564 test_data(GPIO_E, 11),
565 test_open_drain);
566 qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr1",
567 test_data(GPIO_A, 12),
568 test_bsrr_brr);
569 qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr2",
570 test_data(GPIO_D, 0),
571 test_bsrr_brr);
572 qtest_add_func("stm32l4x5/gpio/test_clock_enable",
573 test_clock_enable);
574
575 qtest_start("-machine b-l475e-iot01a");
576 ret = g_test_run();
577 qtest_end();
578
579 return ret;
580 }
581