14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 24b5e93edSEtienne Carriere /* 34b5e93edSEtienne Carriere * Copyright (c) 2017-2019, STMicroelectronics 44b5e93edSEtienne Carriere * 54b5e93edSEtienne Carriere * STM32 GPIO driver is used as pin controller for stm32mp SoCs. 64b5e93edSEtienne Carriere * The driver API is defined in header file stm32_gpio.h. 74b5e93edSEtienne Carriere */ 84b5e93edSEtienne Carriere 94b5e93edSEtienne Carriere #include <assert.h> 104b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h> 114b5e93edSEtienne Carriere #include <io.h> 124b5e93edSEtienne Carriere #include <kernel/dt.h> 13*65401337SJens Wiklander #include <kernel/boot.h> 144b5e93edSEtienne Carriere #include <kernel/panic.h> 154b5e93edSEtienne Carriere #include <kernel/spinlock.h> 16a2fc83d1SJerome Forissier #include <libfdt.h> 174b5e93edSEtienne Carriere #include <mm/core_memprot.h> 184b5e93edSEtienne Carriere #include <stdbool.h> 194b5e93edSEtienne Carriere #include <stm32_util.h> 204b5e93edSEtienne Carriere #include <trace.h> 214b5e93edSEtienne Carriere #include <util.h> 224b5e93edSEtienne Carriere 234b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 244b5e93edSEtienne Carriere 254b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET 0x00 264b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET 0x04 274b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET 0x08 284b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET 0x0c 294b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET 0x10 304b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET 0x14 314b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET 0x18 324b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET 0x20 334b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET 0x24 344b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET 0x30 354b5e93edSEtienne Carriere 364b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT 0x8 374b5e93edSEtienne Carriere 384b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 394b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 404b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 414b5e93edSEtienne Carriere #define GPIO_ALTERNATE_MASK GENMASK_32(15, 0) 424b5e93edSEtienne Carriere 434b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT 12 444b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 454b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT 8 464b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 474b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 484b5e93edSEtienne Carriere 494b5e93edSEtienne Carriere static unsigned int gpio_lock; 504b5e93edSEtienne Carriere 514b5e93edSEtienne Carriere /* Save to output @cfg the current GPIO (@bank/@pin) configuration */ 524b5e93edSEtienne Carriere static void get_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) 534b5e93edSEtienne Carriere { 544d22155cSEtienne Carriere vaddr_t base = stm32_get_gpio_bank_base(bank); 554b5e93edSEtienne Carriere unsigned int clock = stm32_get_gpio_bank_clock(bank); 564b5e93edSEtienne Carriere 574b5e93edSEtienne Carriere stm32_clock_enable(clock); 584b5e93edSEtienne Carriere 594b5e93edSEtienne Carriere /* 604b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 614b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 624b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 634b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 644b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 654b5e93edSEtienne Carriere */ 66918bb3a5SEtienne Carriere cfg->mode = (io_read32(base + GPIO_MODER_OFFSET) >> (pin << 1)) & 674b5e93edSEtienne Carriere GPIO_MODE_MASK; 684b5e93edSEtienne Carriere 69918bb3a5SEtienne Carriere cfg->otype = (io_read32(base + GPIO_OTYPER_OFFSET) >> pin) & 1; 704b5e93edSEtienne Carriere 71918bb3a5SEtienne Carriere cfg->ospeed = (io_read32(base + GPIO_OSPEEDR_OFFSET) >> (pin << 1)) & 724b5e93edSEtienne Carriere GPIO_OSPEED_MASK; 734b5e93edSEtienne Carriere 74918bb3a5SEtienne Carriere cfg->pupd = (io_read32(base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 754b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 764b5e93edSEtienne Carriere 77918bb3a5SEtienne Carriere cfg->od = (io_read32(base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 784b5e93edSEtienne Carriere 794b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 80918bb3a5SEtienne Carriere cfg->af = (io_read32(base + GPIO_AFRL_OFFSET) >> (pin << 2)) & 814b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 824b5e93edSEtienne Carriere else 83918bb3a5SEtienne Carriere cfg->af = (io_read32(base + GPIO_AFRH_OFFSET) >> 844b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 854b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 864b5e93edSEtienne Carriere 874b5e93edSEtienne Carriere stm32_clock_disable(clock); 884b5e93edSEtienne Carriere } 894b5e93edSEtienne Carriere 904b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 914b5e93edSEtienne Carriere static void set_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) 924b5e93edSEtienne Carriere { 934d22155cSEtienne Carriere vaddr_t base = stm32_get_gpio_bank_base(bank); 944b5e93edSEtienne Carriere unsigned int clock = stm32_get_gpio_bank_clock(bank); 95c4cab2bbSEtienne Carriere uint32_t exceptions = cpu_spin_lock_xsave(&gpio_lock); 964b5e93edSEtienne Carriere 974b5e93edSEtienne Carriere stm32_clock_enable(clock); 984b5e93edSEtienne Carriere 994b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 1004b5e93edSEtienne Carriere io_clrsetbits32(base + GPIO_MODER_OFFSET, 1014b5e93edSEtienne Carriere GPIO_MODE_MASK << (pin << 1), 1024b5e93edSEtienne Carriere cfg->mode << (pin << 1)); 1034b5e93edSEtienne Carriere 1044b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 1054b5e93edSEtienne Carriere io_clrsetbits32(base + GPIO_OTYPER_OFFSET, BIT(pin), cfg->otype << pin); 1064b5e93edSEtienne Carriere 1074b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 1084b5e93edSEtienne Carriere io_clrsetbits32(base + GPIO_OSPEEDR_OFFSET, 1094b5e93edSEtienne Carriere GPIO_OSPEED_MASK << (pin << 1), 1104b5e93edSEtienne Carriere cfg->ospeed << (pin << 1)); 1114b5e93edSEtienne Carriere 1124b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 1134b5e93edSEtienne Carriere io_clrsetbits32(base + GPIO_PUPDR_OFFSET, BIT(pin), 1144b5e93edSEtienne Carriere cfg->pupd << (pin << 1)); 1154b5e93edSEtienne Carriere 1164b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 1174b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 1184b5e93edSEtienne Carriere io_clrsetbits32(base + GPIO_AFRL_OFFSET, 1194b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK << (pin << 2), 1204b5e93edSEtienne Carriere cfg->af << (pin << 2)); 1214b5e93edSEtienne Carriere } else { 1224b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 1234b5e93edSEtienne Carriere 1244b5e93edSEtienne Carriere io_clrsetbits32(base + GPIO_AFRH_OFFSET, 1254b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK << shift, 1264b5e93edSEtienne Carriere cfg->af << shift); 1274b5e93edSEtienne Carriere } 1284b5e93edSEtienne Carriere 1294b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 1304b5e93edSEtienne Carriere io_clrsetbits32(base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 1314b5e93edSEtienne Carriere 1324b5e93edSEtienne Carriere stm32_clock_disable(clock); 133c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 1344b5e93edSEtienne Carriere } 1354b5e93edSEtienne Carriere 1364b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 1374b5e93edSEtienne Carriere { 13810bcbd6cSEtienne Carriere size_t n = 0; 1394b5e93edSEtienne Carriere 1404b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 1414b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 1424b5e93edSEtienne Carriere &pinctrl[n].active_cfg); 1434b5e93edSEtienne Carriere } 1444b5e93edSEtienne Carriere 1454b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 1464b5e93edSEtienne Carriere { 14710bcbd6cSEtienne Carriere size_t n = 0; 1484b5e93edSEtienne Carriere 1494b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 1504b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 1514b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 1524b5e93edSEtienne Carriere } 1534b5e93edSEtienne Carriere 1544b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 1554b5e93edSEtienne Carriere { 15610bcbd6cSEtienne Carriere size_t n = 0; 1574b5e93edSEtienne Carriere 1584b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 1594b5e93edSEtienne Carriere get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 1604b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 1614b5e93edSEtienne Carriere } 1624b5e93edSEtienne Carriere 1634b5e93edSEtienne Carriere #ifdef CFG_DT 16442f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */ 1654b5e93edSEtienne Carriere static void ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) 1664b5e93edSEtienne Carriere { 16710bcbd6cSEtienne Carriere int pinctrl_subnode = 0; 1684b5e93edSEtienne Carriere 1694b5e93edSEtienne Carriere fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { 17010bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 1714b5e93edSEtienne Carriere 1724b5e93edSEtienne Carriere if (fdt_getprop(fdt, pinctrl_subnode, 1734b5e93edSEtienne Carriere "gpio-controller", NULL) == NULL) 1744b5e93edSEtienne Carriere continue; 1754b5e93edSEtienne Carriere 1764b5e93edSEtienne Carriere /* Check bank register offset matches platform assumptions */ 1774b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); 1784b5e93edSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 179563f6249SEtienne Carriere continue; 1804b5e93edSEtienne Carriere 1814b5e93edSEtienne Carriere /* Check bank clock matches platform assumptions */ 1824b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, pinctrl_subnode, "clocks", NULL); 1834b5e93edSEtienne Carriere if (!cuint) 1844b5e93edSEtienne Carriere panic(); 1854b5e93edSEtienne Carriere cuint++; 1864b5e93edSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_clock(bank)) 1874b5e93edSEtienne Carriere panic(); 1884b5e93edSEtienne Carriere 1894b5e93edSEtienne Carriere /* Check controller is enabled */ 1904b5e93edSEtienne Carriere if (_fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED) 1914b5e93edSEtienne Carriere panic(); 1924b5e93edSEtienne Carriere 1934b5e93edSEtienne Carriere return; 1944b5e93edSEtienne Carriere } 1954b5e93edSEtienne Carriere 1964b5e93edSEtienne Carriere panic(); 1974b5e93edSEtienne Carriere } 1984b5e93edSEtienne Carriere 1994b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 2004b5e93edSEtienne Carriere static int get_pinctrl_from_fdt(void *fdt, int node, 2014b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 2024b5e93edSEtienne Carriere { 2034b5e93edSEtienne Carriere const fdt32_t *cuint, *slewrate; 20410bcbd6cSEtienne Carriere int len = 0; 20510bcbd6cSEtienne Carriere int pinctrl_node = 0; 20610bcbd6cSEtienne Carriere uint32_t i = 0; 2074b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 2084b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 2094b5e93edSEtienne Carriere size_t found = 0; 2104b5e93edSEtienne Carriere 2114b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 2124b5e93edSEtienne Carriere if (!cuint) 2134b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 2144b5e93edSEtienne Carriere 2154b5e93edSEtienne Carriere pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); 2164b5e93edSEtienne Carriere if (pinctrl_node < 0) 2174b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 2184b5e93edSEtienne Carriere 2194b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 2204b5e93edSEtienne Carriere if (slewrate) 2214b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 2224b5e93edSEtienne Carriere 2234b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 2244b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 2254b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 2264b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 2274b5e93edSEtienne Carriere 2284b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 22910bcbd6cSEtienne Carriere uint32_t pincfg = 0; 23010bcbd6cSEtienne Carriere uint32_t bank = 0; 23110bcbd6cSEtienne Carriere uint32_t pin = 0; 23210bcbd6cSEtienne Carriere uint32_t mode = 0; 2334b5e93edSEtienne Carriere uint32_t alternate = 0; 2344b5e93edSEtienne Carriere bool opendrain = false; 2354b5e93edSEtienne Carriere 2364b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 2374b5e93edSEtienne Carriere cuint++; 2384b5e93edSEtienne Carriere 2394b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 2404b5e93edSEtienne Carriere 2414b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 2424b5e93edSEtienne Carriere 2434b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 2444b5e93edSEtienne Carriere 2454b5e93edSEtienne Carriere switch (mode) { 2464b5e93edSEtienne Carriere case 0: 2474b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 2484b5e93edSEtienne Carriere break; 2494b5e93edSEtienne Carriere case 1: 2504b5e93edSEtienne Carriere case 2: 2514b5e93edSEtienne Carriere case 3: 2524b5e93edSEtienne Carriere case 4: 2534b5e93edSEtienne Carriere case 5: 2544b5e93edSEtienne Carriere case 6: 2554b5e93edSEtienne Carriere case 7: 2564b5e93edSEtienne Carriere case 8: 2574b5e93edSEtienne Carriere case 9: 2584b5e93edSEtienne Carriere case 10: 2594b5e93edSEtienne Carriere case 11: 2604b5e93edSEtienne Carriere case 12: 2614b5e93edSEtienne Carriere case 13: 2624b5e93edSEtienne Carriere case 14: 2634b5e93edSEtienne Carriere case 15: 2644b5e93edSEtienne Carriere case 16: 2654b5e93edSEtienne Carriere alternate = mode - 1U; 2664b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 2674b5e93edSEtienne Carriere break; 2684b5e93edSEtienne Carriere case 17: 2694b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 2704b5e93edSEtienne Carriere break; 2714b5e93edSEtienne Carriere default: 2724b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 2734b5e93edSEtienne Carriere break; 2744b5e93edSEtienne Carriere } 2754b5e93edSEtienne Carriere 2764b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 2774b5e93edSEtienne Carriere opendrain = true; 2784b5e93edSEtienne Carriere 2794b5e93edSEtienne Carriere /* Check GPIO bank clock/base address against platform */ 2804b5e93edSEtienne Carriere ckeck_gpio_bank(fdt, bank, pinctrl_node); 2814b5e93edSEtienne Carriere 2824b5e93edSEtienne Carriere if (found < count) { 2834b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 2844b5e93edSEtienne Carriere 2854b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 2864b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 2874b5e93edSEtienne Carriere ref->active_cfg.mode = mode; 2884b5e93edSEtienne Carriere ref->active_cfg.otype = opendrain ? 1 : 0; 2894b5e93edSEtienne Carriere ref->active_cfg.ospeed = speed; 2904b5e93edSEtienne Carriere ref->active_cfg.pupd = pull; 2914b5e93edSEtienne Carriere ref->active_cfg.od = 0; 2924b5e93edSEtienne Carriere ref->active_cfg.af = alternate; 2934b5e93edSEtienne Carriere /* Default to analog mode for standby state */ 2944b5e93edSEtienne Carriere ref->standby_cfg.mode = GPIO_MODE_ANALOG; 2954b5e93edSEtienne Carriere ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL; 2964b5e93edSEtienne Carriere } 2974b5e93edSEtienne Carriere 2984b5e93edSEtienne Carriere found++; 2994b5e93edSEtienne Carriere } 3004b5e93edSEtienne Carriere 3014b5e93edSEtienne Carriere return (int)found; 3024b5e93edSEtienne Carriere } 3034b5e93edSEtienne Carriere 3044b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node, 3054b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 3064b5e93edSEtienne Carriere { 30710bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 30810bcbd6cSEtienne Carriere int lenp = 0; 30910bcbd6cSEtienne Carriere int i = 0; 3104b5e93edSEtienne Carriere size_t found = 0; 3114b5e93edSEtienne Carriere 3124b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp); 3134b5e93edSEtienne Carriere if (!cuint) 3144b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3154b5e93edSEtienne Carriere 3164b5e93edSEtienne Carriere for (i = 0; i < (lenp / 4); i++) { 31710bcbd6cSEtienne Carriere int node = 0; 31810bcbd6cSEtienne Carriere int subnode = 0; 3194b5e93edSEtienne Carriere 3204b5e93edSEtienne Carriere node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 3214b5e93edSEtienne Carriere if (node < 0) 3224b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3234b5e93edSEtienne Carriere 3244b5e93edSEtienne Carriere fdt_for_each_subnode(subnode, fdt, node) { 32510bcbd6cSEtienne Carriere size_t n = 0; 32610bcbd6cSEtienne Carriere int rc = 0; 3274b5e93edSEtienne Carriere 3284b5e93edSEtienne Carriere if (count > found) 3294b5e93edSEtienne Carriere n = count - found; 3304b5e93edSEtienne Carriere else 3314b5e93edSEtienne Carriere n = 0; 3324b5e93edSEtienne Carriere 3334b5e93edSEtienne Carriere rc = get_pinctrl_from_fdt(fdt, subnode, 3344b5e93edSEtienne Carriere &pinctrl[found], n); 3354b5e93edSEtienne Carriere if (rc < 0) 3364b5e93edSEtienne Carriere return rc; 3374b5e93edSEtienne Carriere 3384b5e93edSEtienne Carriere found += (size_t)rc; 3394b5e93edSEtienne Carriere } 3404b5e93edSEtienne Carriere 3414b5e93edSEtienne Carriere cuint++; 3424b5e93edSEtienne Carriere } 3434b5e93edSEtienne Carriere 3444b5e93edSEtienne Carriere return (int)found; 3454b5e93edSEtienne Carriere } 346a3104caaSEtienne Carriere 347a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank) 348a3104caaSEtienne Carriere { 349a3104caaSEtienne Carriere int node = 0; 350a3104caaSEtienne Carriere const fdt32_t *cuint = NULL; 351a3104caaSEtienne Carriere 352a3104caaSEtienne Carriere fdt_for_each_subnode(node, fdt, pinctrl_node) { 353a3104caaSEtienne Carriere if (!fdt_getprop(fdt, node, "gpio-controller", NULL)) 354a3104caaSEtienne Carriere continue; 355a3104caaSEtienne Carriere 356a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "reg", NULL); 357a3104caaSEtienne Carriere if (!cuint) 358a3104caaSEtienne Carriere continue; 359a3104caaSEtienne Carriere 360a3104caaSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 361a3104caaSEtienne Carriere continue; 362a3104caaSEtienne Carriere 363a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "ngpios", NULL); 364a3104caaSEtienne Carriere if (!cuint) 365a3104caaSEtienne Carriere panic(); 366a3104caaSEtienne Carriere 367a3104caaSEtienne Carriere return (int)fdt32_to_cpu(*cuint); 368a3104caaSEtienne Carriere } 369a3104caaSEtienne Carriere 370a3104caaSEtienne Carriere return -1; 371a3104caaSEtienne Carriere } 3724b5e93edSEtienne Carriere #endif /*CFG_DT*/ 3734b5e93edSEtienne Carriere 3744b5e93edSEtienne Carriere static __maybe_unused bool valid_gpio_config(unsigned int bank, 3754b5e93edSEtienne Carriere unsigned int pin, bool input) 3764b5e93edSEtienne Carriere { 3774d22155cSEtienne Carriere vaddr_t base = stm32_get_gpio_bank_base(bank); 378918bb3a5SEtienne Carriere uint32_t mode = (io_read32(base + GPIO_MODER_OFFSET) >> (pin << 1)) & 3794b5e93edSEtienne Carriere GPIO_MODE_MASK; 3804b5e93edSEtienne Carriere 3814b5e93edSEtienne Carriere if (pin > GPIO_PIN_MAX) 3824b5e93edSEtienne Carriere return false; 3834b5e93edSEtienne Carriere 3844b5e93edSEtienne Carriere if (input) 3854b5e93edSEtienne Carriere return mode == GPIO_MODE_INPUT; 3864b5e93edSEtienne Carriere else 3874b5e93edSEtienne Carriere return mode == GPIO_MODE_OUTPUT; 3884b5e93edSEtienne Carriere } 3894b5e93edSEtienne Carriere 3904b5e93edSEtienne Carriere int stm32_gpio_get_input_level(unsigned int bank, unsigned int pin) 3914b5e93edSEtienne Carriere { 3924d22155cSEtienne Carriere vaddr_t base = stm32_get_gpio_bank_base(bank); 3934b5e93edSEtienne Carriere unsigned int clock = stm32_get_gpio_bank_clock(bank); 3944b5e93edSEtienne Carriere int rc = 0; 3954b5e93edSEtienne Carriere 3964b5e93edSEtienne Carriere assert(valid_gpio_config(bank, pin, true)); 3974b5e93edSEtienne Carriere 3984b5e93edSEtienne Carriere stm32_clock_enable(clock); 3994b5e93edSEtienne Carriere 400918bb3a5SEtienne Carriere if (io_read32(base + GPIO_IDR_OFFSET) == BIT(pin)) 4014b5e93edSEtienne Carriere rc = 1; 4024b5e93edSEtienne Carriere 4034b5e93edSEtienne Carriere stm32_clock_disable(clock); 4044b5e93edSEtienne Carriere 4054b5e93edSEtienne Carriere return rc; 4064b5e93edSEtienne Carriere } 4074b5e93edSEtienne Carriere 4084b5e93edSEtienne Carriere void stm32_gpio_set_output_level(unsigned int bank, unsigned int pin, int level) 4094b5e93edSEtienne Carriere { 4104d22155cSEtienne Carriere vaddr_t base = stm32_get_gpio_bank_base(bank); 4114b5e93edSEtienne Carriere unsigned int clock = stm32_get_gpio_bank_clock(bank); 4124b5e93edSEtienne Carriere 4134b5e93edSEtienne Carriere assert(valid_gpio_config(bank, pin, false)); 4144b5e93edSEtienne Carriere 4154b5e93edSEtienne Carriere stm32_clock_enable(clock); 4164b5e93edSEtienne Carriere 4174b5e93edSEtienne Carriere if (level) 418918bb3a5SEtienne Carriere io_write32(base + GPIO_BSRR_OFFSET, BIT(pin)); 4194b5e93edSEtienne Carriere else 420918bb3a5SEtienne Carriere io_write32(base + GPIO_BSRR_OFFSET, BIT(pin + 16)); 4214b5e93edSEtienne Carriere 4224b5e93edSEtienne Carriere stm32_clock_disable(clock); 4234b5e93edSEtienne Carriere } 4244b5e93edSEtienne Carriere 4254b5e93edSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank, unsigned int pin, bool secure) 4264b5e93edSEtienne Carriere { 4274d22155cSEtienne Carriere vaddr_t base = stm32_get_gpio_bank_base(bank); 4284b5e93edSEtienne Carriere unsigned int clock = stm32_get_gpio_bank_clock(bank); 429c4cab2bbSEtienne Carriere uint32_t exceptions = cpu_spin_lock_xsave(&gpio_lock); 4304b5e93edSEtienne Carriere 4314b5e93edSEtienne Carriere stm32_clock_enable(clock); 4324b5e93edSEtienne Carriere 4334b5e93edSEtienne Carriere if (secure) 4344b5e93edSEtienne Carriere io_setbits32(base + GPIO_SECR_OFFSET, BIT(pin)); 4354b5e93edSEtienne Carriere else 4364b5e93edSEtienne Carriere io_clrbits32(base + GPIO_SECR_OFFSET, BIT(pin)); 4374b5e93edSEtienne Carriere 4384b5e93edSEtienne Carriere stm32_clock_disable(clock); 439c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 4404b5e93edSEtienne Carriere } 441