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