14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 24b5e93edSEtienne Carriere /* 39818a481SEtienne Carriere * Copyright (c) 2017-2023, STMicroelectronics 44b5e93edSEtienne Carriere * 54b5e93edSEtienne Carriere * STM32 GPIO driver is used as pin controller for stm32mp SoCs. 64b5e93edSEtienne Carriere */ 74b5e93edSEtienne Carriere 84b5e93edSEtienne Carriere #include <assert.h> 997391ffbSEtienne Carriere #include <drivers/clk.h> 1097391ffbSEtienne Carriere #include <drivers/clk_dt.h> 11420a32c5SEtienne Carriere #include <drivers/gpio.h> 124b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h> 134b5e93edSEtienne Carriere #include <io.h> 144b5e93edSEtienne Carriere #include <kernel/dt.h> 1565401337SJens Wiklander #include <kernel/boot.h> 164b5e93edSEtienne Carriere #include <kernel/panic.h> 174b5e93edSEtienne Carriere #include <kernel/spinlock.h> 18a2fc83d1SJerome Forissier #include <libfdt.h> 194b5e93edSEtienne Carriere #include <mm/core_memprot.h> 204b5e93edSEtienne Carriere #include <stdbool.h> 214b5e93edSEtienne Carriere #include <stm32_util.h> 229818a481SEtienne Carriere #include <sys/queue.h> 234b5e93edSEtienne Carriere #include <trace.h> 244b5e93edSEtienne Carriere #include <util.h> 254b5e93edSEtienne Carriere 261001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 271001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 281001585eSEtienne Carriere #endif 291001585eSEtienne Carriere 304b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 314b5e93edSEtienne Carriere 324b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET 0x00 334b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET 0x04 344b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET 0x08 354b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET 0x0c 364b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET 0x10 374b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET 0x14 384b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET 0x18 394b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET 0x20 404b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET 0x24 414b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET 0x30 424b5e93edSEtienne Carriere 434b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT 0x8 444b5e93edSEtienne Carriere 454b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 464b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 474b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 48729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 494b5e93edSEtienne Carriere 504b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT 12 514b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 524b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT 8 534b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 544b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 554b5e93edSEtienne Carriere 569818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 579818a481SEtienne Carriere 589818a481SEtienne Carriere /** 599818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 609818a481SEtienne Carriere * 619818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 629818a481SEtienne Carriere * @clock: clock identifier. 63420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 649818a481SEtienne Carriere * @ngpios: number of GPIOs. 659818a481SEtienne Carriere * @bank_id: Id of the bank. 669818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 679818a481SEtienne Carriere * @sec_support: True if bank supports pin security protection, otherwise false 689818a481SEtienne Carriere * @seccfgr: Secure configuration register value. 699818a481SEtienne Carriere * @link: Link in bank list 709818a481SEtienne Carriere */ 719818a481SEtienne Carriere struct stm32_gpio_bank { 729818a481SEtienne Carriere vaddr_t base; 739818a481SEtienne Carriere struct clk *clock; 74420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 759818a481SEtienne Carriere unsigned int ngpios; 769818a481SEtienne Carriere unsigned int bank_id; 779818a481SEtienne Carriere unsigned int lock; 789818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 799818a481SEtienne Carriere }; 809818a481SEtienne Carriere 814b5e93edSEtienne Carriere static unsigned int gpio_lock; 824b5e93edSEtienne Carriere 839818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 849818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 859818a481SEtienne Carriere 86420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 87420a32c5SEtienne Carriere 88420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 89420a32c5SEtienne Carriere { 90420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 91420a32c5SEtienne Carriere } 92420a32c5SEtienne Carriere 93420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 94420a32c5SEtienne Carriere unsigned int gpio_pin) 95420a32c5SEtienne Carriere { 96420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 97420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 98420a32c5SEtienne Carriere unsigned int reg_offset = 0; 99420a32c5SEtienne Carriere unsigned int mode = 0; 100420a32c5SEtienne Carriere 101420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1022fd102ebSEtienne Carriere 1032fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1042fd102ebSEtienne Carriere panic(); 105420a32c5SEtienne Carriere 106420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 107420a32c5SEtienne Carriere GPIO_MODE_MASK; 108420a32c5SEtienne Carriere 109420a32c5SEtienne Carriere switch (mode) { 110420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 111420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 112420a32c5SEtienne Carriere break; 113420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 114420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 115420a32c5SEtienne Carriere break; 116420a32c5SEtienne Carriere default: 117420a32c5SEtienne Carriere panic(); 118420a32c5SEtienne Carriere } 119420a32c5SEtienne Carriere 120420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 121420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 122420a32c5SEtienne Carriere else 123420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 124420a32c5SEtienne Carriere 125420a32c5SEtienne Carriere clk_disable(bank->clock); 126420a32c5SEtienne Carriere 127420a32c5SEtienne Carriere return level; 128420a32c5SEtienne Carriere } 129420a32c5SEtienne Carriere 130420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 131420a32c5SEtienne Carriere enum gpio_level level) 132420a32c5SEtienne Carriere { 133420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 134420a32c5SEtienne Carriere 135420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1362fd102ebSEtienne Carriere 1372fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1382fd102ebSEtienne Carriere panic(); 139420a32c5SEtienne Carriere 140420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 141420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 142420a32c5SEtienne Carriere 143420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 144420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 145420a32c5SEtienne Carriere else 146420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 147420a32c5SEtienne Carriere 148420a32c5SEtienne Carriere clk_disable(bank->clock); 149420a32c5SEtienne Carriere } 150420a32c5SEtienne Carriere 151420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 152420a32c5SEtienne Carriere unsigned int gpio_pin) 153420a32c5SEtienne Carriere { 154420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 155420a32c5SEtienne Carriere uint32_t mode = 0; 156420a32c5SEtienne Carriere 157420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1582fd102ebSEtienne Carriere 1592fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1602fd102ebSEtienne Carriere panic(); 161420a32c5SEtienne Carriere 162420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 163420a32c5SEtienne Carriere GPIO_MODE_MASK; 164420a32c5SEtienne Carriere 165420a32c5SEtienne Carriere clk_disable(bank->clock); 166420a32c5SEtienne Carriere 167420a32c5SEtienne Carriere switch (mode) { 168420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 169420a32c5SEtienne Carriere return GPIO_DIR_IN; 170420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 171420a32c5SEtienne Carriere return GPIO_DIR_OUT; 172420a32c5SEtienne Carriere default: 173420a32c5SEtienne Carriere panic(); 174420a32c5SEtienne Carriere } 175420a32c5SEtienne Carriere } 176420a32c5SEtienne Carriere 177420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 178420a32c5SEtienne Carriere unsigned int gpio_pin, 179420a32c5SEtienne Carriere enum gpio_dir direction) 180420a32c5SEtienne Carriere { 181420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 182420a32c5SEtienne Carriere uint32_t exceptions = 0; 183420a32c5SEtienne Carriere uint32_t mode = 0; 184420a32c5SEtienne Carriere 185420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 186420a32c5SEtienne Carriere 187420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 188420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 189420a32c5SEtienne Carriere else 190420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 191420a32c5SEtienne Carriere 1922fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1932fd102ebSEtienne Carriere panic(); 194420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 195420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 196420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 197420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 198420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 199420a32c5SEtienne Carriere clk_disable(bank->clock); 200420a32c5SEtienne Carriere } 201420a32c5SEtienne Carriere 202420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 203420a32c5SEtienne Carriere struct gpio *gpio) 204420a32c5SEtienne Carriere { 205420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 206420a32c5SEtienne Carriere free(gpio); 207420a32c5SEtienne Carriere } 208420a32c5SEtienne Carriere 209420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 210420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 211420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 212420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 213420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 214420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 215420a32c5SEtienne Carriere }; 216420a32c5SEtienne Carriere 217420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 218420a32c5SEtienne Carriere { 219420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 220420a32c5SEtienne Carriere } 221420a32c5SEtienne Carriere 222077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 2234b5e93edSEtienne Carriere { 224077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 2254b5e93edSEtienne Carriere 226077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 227077d486eSEtienne Carriere if (bank_id == bank->bank_id) 228077d486eSEtienne Carriere return bank; 229077d486eSEtienne Carriere 230077d486eSEtienne Carriere panic(); 231077d486eSEtienne Carriere } 232077d486eSEtienne Carriere 233077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 234077d486eSEtienne Carriere static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 235077d486eSEtienne Carriere { 236077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 237077d486eSEtienne Carriere 238077d486eSEtienne Carriere if (clk_enable(bank->clock)) 239077d486eSEtienne Carriere panic(); 2404b5e93edSEtienne Carriere 2414b5e93edSEtienne Carriere /* 2424b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 2434b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 2444b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 2454b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 2464b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 2474b5e93edSEtienne Carriere */ 248077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 2494b5e93edSEtienne Carriere GPIO_MODE_MASK; 2504b5e93edSEtienne Carriere 251077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 2524b5e93edSEtienne Carriere 253077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 254077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 2554b5e93edSEtienne Carriere 256077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 2574b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 2584b5e93edSEtienne Carriere 259077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 2604b5e93edSEtienne Carriere 2614b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 262077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 263077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 2644b5e93edSEtienne Carriere else 265077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 2664b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 2674b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 2684b5e93edSEtienne Carriere 269077d486eSEtienne Carriere clk_disable(bank->clock); 2704b5e93edSEtienne Carriere } 2714b5e93edSEtienne Carriere 2724b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 273077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 2744b5e93edSEtienne Carriere { 275077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 27698dfcedaSEtienne Carriere uint32_t exceptions = 0; 2774b5e93edSEtienne Carriere 278077d486eSEtienne Carriere if (clk_enable(bank->clock)) 279077d486eSEtienne Carriere panic(); 28098dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 2814b5e93edSEtienne Carriere 2824b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 283077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 284bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 285bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 2864b5e93edSEtienne Carriere 2874b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 288077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 289bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 2904b5e93edSEtienne Carriere 2914b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 292077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 293bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 294bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 2954b5e93edSEtienne Carriere 2964b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 297077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 298bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 2994b5e93edSEtienne Carriere 3004b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 3014b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 302077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 303bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 304bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 3054b5e93edSEtienne Carriere } else { 3064b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 3074b5e93edSEtienne Carriere 308077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 309bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 310bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 3114b5e93edSEtienne Carriere } 3124b5e93edSEtienne Carriere 3134b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 314077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 3154b5e93edSEtienne Carriere 316c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 31798dfcedaSEtienne Carriere clk_disable(bank->clock); 3184b5e93edSEtienne Carriere } 3194b5e93edSEtienne Carriere 3204b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3214b5e93edSEtienne Carriere { 32210bcbd6cSEtienne Carriere size_t n = 0; 3234b5e93edSEtienne Carriere 3244b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3254b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3264b5e93edSEtienne Carriere &pinctrl[n].active_cfg); 3274b5e93edSEtienne Carriere } 3284b5e93edSEtienne Carriere 3294b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3304b5e93edSEtienne Carriere { 33110bcbd6cSEtienne Carriere size_t n = 0; 3324b5e93edSEtienne Carriere 3334b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3344b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3354b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3364b5e93edSEtienne Carriere } 3374b5e93edSEtienne Carriere 3384b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3394b5e93edSEtienne Carriere { 34010bcbd6cSEtienne Carriere size_t n = 0; 3414b5e93edSEtienne Carriere 3424b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3434b5e93edSEtienne Carriere get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3444b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3454b5e93edSEtienne Carriere } 3464b5e93edSEtienne Carriere 34742f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */ 3484b5e93edSEtienne Carriere static void ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) 3494b5e93edSEtienne Carriere { 35010bcbd6cSEtienne Carriere int pinctrl_subnode = 0; 3514b5e93edSEtienne Carriere 3524b5e93edSEtienne Carriere fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { 35310bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 3544b5e93edSEtienne Carriere 3554b5e93edSEtienne Carriere if (fdt_getprop(fdt, pinctrl_subnode, 3564b5e93edSEtienne Carriere "gpio-controller", NULL) == NULL) 3574b5e93edSEtienne Carriere continue; 3584b5e93edSEtienne Carriere 3594b5e93edSEtienne Carriere /* Check bank register offset matches platform assumptions */ 3604b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); 3614b5e93edSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 362563f6249SEtienne Carriere continue; 3634b5e93edSEtienne Carriere 3644b5e93edSEtienne Carriere /* Check controller is enabled */ 365f354a5d8SGatien Chevallier if (fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED) 3664b5e93edSEtienne Carriere panic(); 3674b5e93edSEtienne Carriere 3684b5e93edSEtienne Carriere return; 3694b5e93edSEtienne Carriere } 3704b5e93edSEtienne Carriere 3714b5e93edSEtienne Carriere panic(); 3724b5e93edSEtienne Carriere } 3734b5e93edSEtienne Carriere 3744b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 3754b5e93edSEtienne Carriere static int get_pinctrl_from_fdt(void *fdt, int node, 3764b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 3774b5e93edSEtienne Carriere { 3784b5e93edSEtienne Carriere const fdt32_t *cuint, *slewrate; 37910bcbd6cSEtienne Carriere int len = 0; 38010bcbd6cSEtienne Carriere int pinctrl_node = 0; 38110bcbd6cSEtienne Carriere uint32_t i = 0; 3824b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 3834b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 3844b5e93edSEtienne Carriere size_t found = 0; 3854b5e93edSEtienne Carriere 3864b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 3874b5e93edSEtienne Carriere if (!cuint) 3884b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3894b5e93edSEtienne Carriere 3904b5e93edSEtienne Carriere pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); 3914b5e93edSEtienne Carriere if (pinctrl_node < 0) 3924b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3934b5e93edSEtienne Carriere 3944b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 3954b5e93edSEtienne Carriere if (slewrate) 3964b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 3974b5e93edSEtienne Carriere 3984b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 3994b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 4004b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 4014b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 4024b5e93edSEtienne Carriere 4034b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 40410bcbd6cSEtienne Carriere uint32_t pincfg = 0; 40510bcbd6cSEtienne Carriere uint32_t bank = 0; 40610bcbd6cSEtienne Carriere uint32_t pin = 0; 40710bcbd6cSEtienne Carriere uint32_t mode = 0; 4084b5e93edSEtienne Carriere uint32_t alternate = 0; 409322cf9e3SEtienne Carriere uint32_t odata = 0; 4104b5e93edSEtienne Carriere bool opendrain = false; 4114b5e93edSEtienne Carriere 4124b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 4134b5e93edSEtienne Carriere cuint++; 4144b5e93edSEtienne Carriere 4154b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 4164b5e93edSEtienne Carriere 4174b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 4184b5e93edSEtienne Carriere 4194b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 4204b5e93edSEtienne Carriere 4214b5e93edSEtienne Carriere switch (mode) { 4224b5e93edSEtienne Carriere case 0: 4234b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 4244b5e93edSEtienne Carriere break; 4254b5e93edSEtienne Carriere case 1: 4264b5e93edSEtienne Carriere case 2: 4274b5e93edSEtienne Carriere case 3: 4284b5e93edSEtienne Carriere case 4: 4294b5e93edSEtienne Carriere case 5: 4304b5e93edSEtienne Carriere case 6: 4314b5e93edSEtienne Carriere case 7: 4324b5e93edSEtienne Carriere case 8: 4334b5e93edSEtienne Carriere case 9: 4344b5e93edSEtienne Carriere case 10: 4354b5e93edSEtienne Carriere case 11: 4364b5e93edSEtienne Carriere case 12: 4374b5e93edSEtienne Carriere case 13: 4384b5e93edSEtienne Carriere case 14: 4394b5e93edSEtienne Carriere case 15: 4404b5e93edSEtienne Carriere case 16: 4414b5e93edSEtienne Carriere alternate = mode - 1U; 4424b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 4434b5e93edSEtienne Carriere break; 4444b5e93edSEtienne Carriere case 17: 4454b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 4464b5e93edSEtienne Carriere break; 4474b5e93edSEtienne Carriere default: 4484b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 4494b5e93edSEtienne Carriere break; 4504b5e93edSEtienne Carriere } 4514b5e93edSEtienne Carriere 4524b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 4534b5e93edSEtienne Carriere opendrain = true; 4544b5e93edSEtienne Carriere 455322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 456322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 457322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 458322cf9e3SEtienne Carriere odata = 1; 459322cf9e3SEtienne Carriere } 460322cf9e3SEtienne Carriere 461322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 462322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 463322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 464322cf9e3SEtienne Carriere odata = 0; 465322cf9e3SEtienne Carriere } 466322cf9e3SEtienne Carriere 4674b5e93edSEtienne Carriere /* Check GPIO bank clock/base address against platform */ 4684b5e93edSEtienne Carriere ckeck_gpio_bank(fdt, bank, pinctrl_node); 4694b5e93edSEtienne Carriere 4704b5e93edSEtienne Carriere if (found < count) { 4714b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 4724b5e93edSEtienne Carriere 4734b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 4744b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 4754b5e93edSEtienne Carriere ref->active_cfg.mode = mode; 4764b5e93edSEtienne Carriere ref->active_cfg.otype = opendrain ? 1 : 0; 4774b5e93edSEtienne Carriere ref->active_cfg.ospeed = speed; 4784b5e93edSEtienne Carriere ref->active_cfg.pupd = pull; 479322cf9e3SEtienne Carriere ref->active_cfg.od = odata; 4804b5e93edSEtienne Carriere ref->active_cfg.af = alternate; 4814b5e93edSEtienne Carriere /* Default to analog mode for standby state */ 4824b5e93edSEtienne Carriere ref->standby_cfg.mode = GPIO_MODE_ANALOG; 4834b5e93edSEtienne Carriere ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL; 4844b5e93edSEtienne Carriere } 4854b5e93edSEtienne Carriere 4864b5e93edSEtienne Carriere found++; 4874b5e93edSEtienne Carriere } 4884b5e93edSEtienne Carriere 4894b5e93edSEtienne Carriere return (int)found; 4904b5e93edSEtienne Carriere } 4914b5e93edSEtienne Carriere 492420a32c5SEtienne Carriere static struct gpio *stm32_gpio_get_dt(struct dt_pargs *pargs, 493420a32c5SEtienne Carriere void *data, TEE_Result *res) 494420a32c5SEtienne Carriere { 495420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 496420a32c5SEtienne Carriere struct gpio *gpio = NULL; 497420a32c5SEtienne Carriere unsigned int shift_1b = 0; 498420a32c5SEtienne Carriere unsigned int shift_2b = 0; 499420a32c5SEtienne Carriere uint32_t exceptions = 0; 500420a32c5SEtienne Carriere uint32_t otype = 0; 501420a32c5SEtienne Carriere uint32_t pupd = 0; 502420a32c5SEtienne Carriere uint32_t mode = 0; 503420a32c5SEtienne Carriere 504420a32c5SEtienne Carriere gpio = gpio_dt_alloc_pin(pargs, res); 505420a32c5SEtienne Carriere if (*res) 506420a32c5SEtienne Carriere return NULL; 507420a32c5SEtienne Carriere 508420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 509420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 510420a32c5SEtienne Carriere free(gpio); 511420a32c5SEtienne Carriere return NULL; 512420a32c5SEtienne Carriere } 513420a32c5SEtienne Carriere 514420a32c5SEtienne Carriere shift_1b = gpio->pin; 515420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 516420a32c5SEtienne Carriere 517420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 518420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 519420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 520420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 521420a32c5SEtienne Carriere else 522420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 523420a32c5SEtienne Carriere 524420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 525420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 526420a32c5SEtienne Carriere else 527420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 528420a32c5SEtienne Carriere 529420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 530420a32c5SEtienne Carriere panic(); 531420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 532420a32c5SEtienne Carriere 533420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 534420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 535420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 536420a32c5SEtienne Carriere 537420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 538420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 539420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 540420a32c5SEtienne Carriere 541420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 542420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 543420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 544420a32c5SEtienne Carriere 545420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 546420a32c5SEtienne Carriere clk_disable(bank->clock); 547420a32c5SEtienne Carriere 548420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 549420a32c5SEtienne Carriere 550420a32c5SEtienne Carriere *res = TEE_SUCCESS; 551420a32c5SEtienne Carriere 552420a32c5SEtienne Carriere return gpio; 553420a32c5SEtienne Carriere } 554420a32c5SEtienne Carriere 5559818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 5569818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 5579818a481SEtienne Carriere { 5589818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 5599818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5609818a481SEtienne Carriere int len = 0; 5619818a481SEtienne Carriere 5629818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 5639818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 5649818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 5659818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 5669818a481SEtienne Carriere 5679818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 5689818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 5699818a481SEtienne Carriere panic("Wrong st,bank-name property"); 5709818a481SEtienne Carriere 5719818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 5729818a481SEtienne Carriere } 5739818a481SEtienne Carriere 5749818a481SEtienne Carriere /* 5759818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 5769818a481SEtienne Carriere * registered in the GPIO bank link. 5779818a481SEtienne Carriere */ 5789818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 5799818a481SEtienne Carriere { 5809818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 5819818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5829818a481SEtienne Carriere 5839818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 5849818a481SEtienne Carriere if (bank->bank_id == bank_id) 5859818a481SEtienne Carriere return true; 5869818a481SEtienne Carriere 5879818a481SEtienne Carriere return false; 5889818a481SEtienne Carriere } 5899818a481SEtienne Carriere 5909818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 5919818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 5929818a481SEtienne Carriere const void *compat_data __unused, 5939818a481SEtienne Carriere int range_offset, 5949818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 5959818a481SEtienne Carriere { 5969818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 5979818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5989818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5999818a481SEtienne Carriere struct io_pa_va pa_va = { }; 6009818a481SEtienne Carriere struct clk *clk = NULL; 6019818a481SEtienne Carriere size_t blen = 0; 6029818a481SEtienne Carriere paddr_t pa = 0; 6039818a481SEtienne Carriere int len = 0; 6049818a481SEtienne Carriere int i = 0; 6059818a481SEtienne Carriere 6069818a481SEtienne Carriere assert(out_bank); 6079818a481SEtienne Carriere 6089818a481SEtienne Carriere /* Probe deferrable devices first */ 6099818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 6109818a481SEtienne Carriere if (res) 6119818a481SEtienne Carriere return res; 6129818a481SEtienne Carriere 6139818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 6149818a481SEtienne Carriere if (!bank) 6159818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 6169818a481SEtienne Carriere 6179818a481SEtienne Carriere /* 6189818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 6199818a481SEtienne Carriere * but consider also the "ranges" translation property 6209818a481SEtienne Carriere */ 6219818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 6229818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 6239818a481SEtienne Carriere panic("missing reg property"); 6249818a481SEtienne Carriere 6259818a481SEtienne Carriere pa_va.pa = pa + range_offset; 6269818a481SEtienne Carriere 6279818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 6289818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 6299818a481SEtienne Carriere panic("missing reg size property"); 6309818a481SEtienne Carriere 6319818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 6329818a481SEtienne Carriere bank->base = io_pa_or_va_secure(&pa_va, blen); 6339818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 6349818a481SEtienne Carriere bank->clock = clk; 635420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 6369818a481SEtienne Carriere 6379818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 6389818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 6399818a481SEtienne Carriere len /= sizeof(*cuint); 6409818a481SEtienne Carriere if (len % 4) 6419818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 6429818a481SEtienne Carriere 6439818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 6449818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 6459818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 6469818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 6479818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 6489818a481SEtienne Carriere cuint += 4; 6499818a481SEtienne Carriere } 6509818a481SEtienne Carriere 6519818a481SEtienne Carriere *out_bank = bank; 6529818a481SEtienne Carriere return TEE_SUCCESS; 6539818a481SEtienne Carriere } 6549818a481SEtienne Carriere 655*be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank) 656*be53ee7bSEtienne Carriere { 657*be53ee7bSEtienne Carriere unsigned int pin = 0; 658*be53ee7bSEtienne Carriere 659*be53ee7bSEtienne Carriere for (pin = 0; pin <= bank->ngpios; pin++) 660*be53ee7bSEtienne Carriere stm32_gpio_set_secure_cfg(bank->bank_id, pin, false); 661*be53ee7bSEtienne Carriere } 662*be53ee7bSEtienne Carriere 6639818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */ 6640e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 6659818a481SEtienne Carriere const void *compat_data) 6669818a481SEtienne Carriere { 6679818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 6689818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6699818a481SEtienne Carriere int range_offs = 0; 6709818a481SEtienne Carriere int b_node = 0; 6719818a481SEtienne Carriere int len = 0; 6729818a481SEtienne Carriere 6739818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 6749818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 6759818a481SEtienne Carriere if (!cuint) 6769818a481SEtienne Carriere panic("missing ranges property"); 6779818a481SEtienne Carriere 6789818a481SEtienne Carriere len /= sizeof(*cuint); 6799818a481SEtienne Carriere if (len == 3) 6809818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 6819818a481SEtienne Carriere 6829818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 6839818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 6849818a481SEtienne Carriere if (cuint) { 6859818a481SEtienne Carriere /* 6869818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 6879818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 6889818a481SEtienne Carriere * bank list. 6899818a481SEtienne Carriere */ 6909818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6919818a481SEtienne Carriere 6929818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 6939818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 6949818a481SEtienne Carriere continue; 6959818a481SEtienne Carriere 6969818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 6979818a481SEtienne Carriere range_offs, &bank); 6989818a481SEtienne Carriere if (res) 6999818a481SEtienne Carriere return res; 7009818a481SEtienne Carriere 701420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 702420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 703420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 704420a32c5SEtienne Carriere if (res) 705420a32c5SEtienne Carriere panic(); 706420a32c5SEtienne Carriere 7079818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 708*be53ee7bSEtienne Carriere 709*be53ee7bSEtienne Carriere if (IS_ENABLED(CFG_STM32MP13)) 710*be53ee7bSEtienne Carriere set_bank_gpio_non_secure(bank); 7119818a481SEtienne Carriere } else { 7129818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 7139818a481SEtienne Carriere panic(); 7149818a481SEtienne Carriere } 7159818a481SEtienne Carriere } 7169818a481SEtienne Carriere 7179818a481SEtienne Carriere return TEE_SUCCESS; 7189818a481SEtienne Carriere } 7199818a481SEtienne Carriere 7204b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node, 7214b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 7224b5e93edSEtienne Carriere { 72310bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 72410bcbd6cSEtienne Carriere int lenp = 0; 72510bcbd6cSEtienne Carriere int i = 0; 7264b5e93edSEtienne Carriere size_t found = 0; 7274b5e93edSEtienne Carriere 7284b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp); 7294b5e93edSEtienne Carriere if (!cuint) 7304b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7314b5e93edSEtienne Carriere 7324b5e93edSEtienne Carriere for (i = 0; i < (lenp / 4); i++) { 73310bcbd6cSEtienne Carriere int node = 0; 73410bcbd6cSEtienne Carriere int subnode = 0; 7354b5e93edSEtienne Carriere 7364b5e93edSEtienne Carriere node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 7374b5e93edSEtienne Carriere if (node < 0) 7384b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7394b5e93edSEtienne Carriere 7404b5e93edSEtienne Carriere fdt_for_each_subnode(subnode, fdt, node) { 74110bcbd6cSEtienne Carriere size_t n = 0; 74210bcbd6cSEtienne Carriere int rc = 0; 7434b5e93edSEtienne Carriere 7444b5e93edSEtienne Carriere if (count > found) 7454b5e93edSEtienne Carriere n = count - found; 7464b5e93edSEtienne Carriere else 7474b5e93edSEtienne Carriere n = 0; 7484b5e93edSEtienne Carriere 7494b5e93edSEtienne Carriere rc = get_pinctrl_from_fdt(fdt, subnode, 7504b5e93edSEtienne Carriere &pinctrl[found], n); 7514b5e93edSEtienne Carriere if (rc < 0) 7524b5e93edSEtienne Carriere return rc; 7534b5e93edSEtienne Carriere 7544b5e93edSEtienne Carriere found += (size_t)rc; 7554b5e93edSEtienne Carriere } 7564b5e93edSEtienne Carriere 7574b5e93edSEtienne Carriere cuint++; 7584b5e93edSEtienne Carriere } 7594b5e93edSEtienne Carriere 7604b5e93edSEtienne Carriere return (int)found; 7614b5e93edSEtienne Carriere } 762a3104caaSEtienne Carriere 763a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank) 764a3104caaSEtienne Carriere { 765a3104caaSEtienne Carriere int node = 0; 766a3104caaSEtienne Carriere const fdt32_t *cuint = NULL; 767a3104caaSEtienne Carriere 768a3104caaSEtienne Carriere fdt_for_each_subnode(node, fdt, pinctrl_node) { 769a3104caaSEtienne Carriere if (!fdt_getprop(fdt, node, "gpio-controller", NULL)) 770a3104caaSEtienne Carriere continue; 771a3104caaSEtienne Carriere 772a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "reg", NULL); 773a3104caaSEtienne Carriere if (!cuint) 774a3104caaSEtienne Carriere continue; 775a3104caaSEtienne Carriere 776a3104caaSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 777a3104caaSEtienne Carriere continue; 778a3104caaSEtienne Carriere 779a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "ngpios", NULL); 780a3104caaSEtienne Carriere if (!cuint) 781a3104caaSEtienne Carriere panic(); 782a3104caaSEtienne Carriere 783a3104caaSEtienne Carriere return (int)fdt32_to_cpu(*cuint); 784a3104caaSEtienne Carriere } 785a3104caaSEtienne Carriere 786a3104caaSEtienne Carriere return -1; 787a3104caaSEtienne Carriere } 7884b5e93edSEtienne Carriere 789077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 790077d486eSEtienne Carriere bool secure) 7914b5e93edSEtienne Carriere { 792077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 79398dfcedaSEtienne Carriere uint32_t exceptions = 0; 7944b5e93edSEtienne Carriere 795077d486eSEtienne Carriere if (clk_enable(bank->clock)) 796077d486eSEtienne Carriere panic(); 79798dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 7984b5e93edSEtienne Carriere 7994b5e93edSEtienne Carriere if (secure) 800077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 8014b5e93edSEtienne Carriere else 802077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 8034b5e93edSEtienne Carriere 804c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 80598dfcedaSEtienne Carriere clk_disable(bank->clock); 8064b5e93edSEtienne Carriere } 8070e0435e2SEtienne Carriere 8080e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 8090e0435e2SEtienne Carriere const void *compat_data) 8100e0435e2SEtienne Carriere { 8110e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 8120e0435e2SEtienne Carriere return dt_stm32_gpio_pinctrl(fdt, node, compat_data); 8130e0435e2SEtienne Carriere } 8140e0435e2SEtienne Carriere 8150e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 8160e0435e2SEtienne Carriere { .compatible = "st,stm32mp135-pinctrl" }, 8170e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-pinctrl" }, 8180e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-z-pinctrl" }, 8190e0435e2SEtienne Carriere { } 8200e0435e2SEtienne Carriere }; 8210e0435e2SEtienne Carriere 8220e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 8230e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 8240e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 8250e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 8260e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 8270e0435e2SEtienne Carriere }; 828