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