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