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