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 26*1001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 27*1001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 28*1001585eSEtienne Carriere #endif 29*1001585eSEtienne 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); 102420a32c5SEtienne Carriere clk_enable(bank->clock); 103420a32c5SEtienne Carriere 104420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 105420a32c5SEtienne Carriere GPIO_MODE_MASK; 106420a32c5SEtienne Carriere 107420a32c5SEtienne Carriere switch (mode) { 108420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 109420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 110420a32c5SEtienne Carriere break; 111420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 112420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 113420a32c5SEtienne Carriere break; 114420a32c5SEtienne Carriere default: 115420a32c5SEtienne Carriere panic(); 116420a32c5SEtienne Carriere } 117420a32c5SEtienne Carriere 118420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 119420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 120420a32c5SEtienne Carriere else 121420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 122420a32c5SEtienne Carriere 123420a32c5SEtienne Carriere clk_disable(bank->clock); 124420a32c5SEtienne Carriere 125420a32c5SEtienne Carriere return level; 126420a32c5SEtienne Carriere } 127420a32c5SEtienne Carriere 128420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 129420a32c5SEtienne Carriere enum gpio_level level) 130420a32c5SEtienne Carriere { 131420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 132420a32c5SEtienne Carriere 133420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 134420a32c5SEtienne Carriere clk_enable(bank->clock); 135420a32c5SEtienne Carriere 136420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 137420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 138420a32c5SEtienne Carriere 139420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 140420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 141420a32c5SEtienne Carriere else 142420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 143420a32c5SEtienne Carriere 144420a32c5SEtienne Carriere clk_disable(bank->clock); 145420a32c5SEtienne Carriere } 146420a32c5SEtienne Carriere 147420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 148420a32c5SEtienne Carriere unsigned int gpio_pin) 149420a32c5SEtienne Carriere { 150420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 151420a32c5SEtienne Carriere uint32_t mode = 0; 152420a32c5SEtienne Carriere 153420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 154420a32c5SEtienne Carriere clk_enable(bank->clock); 155420a32c5SEtienne Carriere 156420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 157420a32c5SEtienne Carriere GPIO_MODE_MASK; 158420a32c5SEtienne Carriere 159420a32c5SEtienne Carriere clk_disable(bank->clock); 160420a32c5SEtienne Carriere 161420a32c5SEtienne Carriere switch (mode) { 162420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 163420a32c5SEtienne Carriere return GPIO_DIR_IN; 164420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 165420a32c5SEtienne Carriere return GPIO_DIR_OUT; 166420a32c5SEtienne Carriere default: 167420a32c5SEtienne Carriere panic(); 168420a32c5SEtienne Carriere } 169420a32c5SEtienne Carriere } 170420a32c5SEtienne Carriere 171420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 172420a32c5SEtienne Carriere unsigned int gpio_pin, 173420a32c5SEtienne Carriere enum gpio_dir direction) 174420a32c5SEtienne Carriere { 175420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 176420a32c5SEtienne Carriere uint32_t exceptions = 0; 177420a32c5SEtienne Carriere uint32_t mode = 0; 178420a32c5SEtienne Carriere 179420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 180420a32c5SEtienne Carriere 181420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 182420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 183420a32c5SEtienne Carriere else 184420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 185420a32c5SEtienne Carriere 186420a32c5SEtienne Carriere clk_enable(bank->clock); 187420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 188420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 189420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 190420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 191420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 192420a32c5SEtienne Carriere clk_disable(bank->clock); 193420a32c5SEtienne Carriere } 194420a32c5SEtienne Carriere 195420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 196420a32c5SEtienne Carriere struct gpio *gpio) 197420a32c5SEtienne Carriere { 198420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 199420a32c5SEtienne Carriere free(gpio); 200420a32c5SEtienne Carriere } 201420a32c5SEtienne Carriere 202420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 203420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 204420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 205420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 206420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 207420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 208420a32c5SEtienne Carriere }; 209420a32c5SEtienne Carriere 210420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 211420a32c5SEtienne Carriere { 212420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 213420a32c5SEtienne Carriere } 214420a32c5SEtienne Carriere 215077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 2164b5e93edSEtienne Carriere { 217077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 2184b5e93edSEtienne Carriere 219077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 220077d486eSEtienne Carriere if (bank_id == bank->bank_id) 221077d486eSEtienne Carriere return bank; 222077d486eSEtienne Carriere 223077d486eSEtienne Carriere panic(); 224077d486eSEtienne Carriere } 225077d486eSEtienne Carriere 226077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 227077d486eSEtienne Carriere static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 228077d486eSEtienne Carriere { 229077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 230077d486eSEtienne Carriere 231077d486eSEtienne Carriere if (clk_enable(bank->clock)) 232077d486eSEtienne Carriere panic(); 2334b5e93edSEtienne Carriere 2344b5e93edSEtienne Carriere /* 2354b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 2364b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 2374b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 2384b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 2394b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 2404b5e93edSEtienne Carriere */ 241077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 2424b5e93edSEtienne Carriere GPIO_MODE_MASK; 2434b5e93edSEtienne Carriere 244077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 2454b5e93edSEtienne Carriere 246077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 247077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 2484b5e93edSEtienne Carriere 249077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 2504b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 2514b5e93edSEtienne Carriere 252077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 2534b5e93edSEtienne Carriere 2544b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 255077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 256077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 2574b5e93edSEtienne Carriere else 258077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 2594b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 2604b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 2614b5e93edSEtienne Carriere 262077d486eSEtienne Carriere clk_disable(bank->clock); 2634b5e93edSEtienne Carriere } 2644b5e93edSEtienne Carriere 2654b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 266077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 2674b5e93edSEtienne Carriere { 268077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 26998dfcedaSEtienne Carriere uint32_t exceptions = 0; 2704b5e93edSEtienne Carriere 271077d486eSEtienne Carriere if (clk_enable(bank->clock)) 272077d486eSEtienne Carriere panic(); 27398dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 2744b5e93edSEtienne Carriere 2754b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 276077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 277bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 278bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 2794b5e93edSEtienne Carriere 2804b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 281077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 282bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 2834b5e93edSEtienne Carriere 2844b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 285077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 286bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 287bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 2884b5e93edSEtienne Carriere 2894b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 290077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 291bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 2924b5e93edSEtienne Carriere 2934b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 2944b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 295077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 296bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 297bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 2984b5e93edSEtienne Carriere } else { 2994b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 3004b5e93edSEtienne Carriere 301077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 302bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 303bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 3044b5e93edSEtienne Carriere } 3054b5e93edSEtienne Carriere 3064b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 307077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 3084b5e93edSEtienne Carriere 309c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 31098dfcedaSEtienne Carriere clk_disable(bank->clock); 3114b5e93edSEtienne Carriere } 3124b5e93edSEtienne Carriere 3134b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3144b5e93edSEtienne Carriere { 31510bcbd6cSEtienne Carriere size_t n = 0; 3164b5e93edSEtienne Carriere 3174b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3184b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3194b5e93edSEtienne Carriere &pinctrl[n].active_cfg); 3204b5e93edSEtienne Carriere } 3214b5e93edSEtienne Carriere 3224b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3234b5e93edSEtienne Carriere { 32410bcbd6cSEtienne Carriere size_t n = 0; 3254b5e93edSEtienne Carriere 3264b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3274b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3284b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3294b5e93edSEtienne Carriere } 3304b5e93edSEtienne Carriere 3314b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3324b5e93edSEtienne Carriere { 33310bcbd6cSEtienne Carriere size_t n = 0; 3344b5e93edSEtienne Carriere 3354b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3364b5e93edSEtienne Carriere get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3374b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3384b5e93edSEtienne Carriere } 3394b5e93edSEtienne Carriere 34042f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */ 3414b5e93edSEtienne Carriere static void ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) 3424b5e93edSEtienne Carriere { 34310bcbd6cSEtienne Carriere int pinctrl_subnode = 0; 3444b5e93edSEtienne Carriere 3454b5e93edSEtienne Carriere fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { 34610bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 3474b5e93edSEtienne Carriere 3484b5e93edSEtienne Carriere if (fdt_getprop(fdt, pinctrl_subnode, 3494b5e93edSEtienne Carriere "gpio-controller", NULL) == NULL) 3504b5e93edSEtienne Carriere continue; 3514b5e93edSEtienne Carriere 3524b5e93edSEtienne Carriere /* Check bank register offset matches platform assumptions */ 3534b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); 3544b5e93edSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 355563f6249SEtienne Carriere continue; 3564b5e93edSEtienne Carriere 3574b5e93edSEtienne Carriere /* Check controller is enabled */ 358f354a5d8SGatien Chevallier if (fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED) 3594b5e93edSEtienne Carriere panic(); 3604b5e93edSEtienne Carriere 3614b5e93edSEtienne Carriere return; 3624b5e93edSEtienne Carriere } 3634b5e93edSEtienne Carriere 3644b5e93edSEtienne Carriere panic(); 3654b5e93edSEtienne Carriere } 3664b5e93edSEtienne Carriere 3674b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 3684b5e93edSEtienne Carriere static int get_pinctrl_from_fdt(void *fdt, int node, 3694b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 3704b5e93edSEtienne Carriere { 3714b5e93edSEtienne Carriere const fdt32_t *cuint, *slewrate; 37210bcbd6cSEtienne Carriere int len = 0; 37310bcbd6cSEtienne Carriere int pinctrl_node = 0; 37410bcbd6cSEtienne Carriere uint32_t i = 0; 3754b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 3764b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 3774b5e93edSEtienne Carriere size_t found = 0; 3784b5e93edSEtienne Carriere 3794b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 3804b5e93edSEtienne Carriere if (!cuint) 3814b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3824b5e93edSEtienne Carriere 3834b5e93edSEtienne Carriere pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); 3844b5e93edSEtienne Carriere if (pinctrl_node < 0) 3854b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3864b5e93edSEtienne Carriere 3874b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 3884b5e93edSEtienne Carriere if (slewrate) 3894b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 3904b5e93edSEtienne Carriere 3914b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 3924b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 3934b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 3944b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 3954b5e93edSEtienne Carriere 3964b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 39710bcbd6cSEtienne Carriere uint32_t pincfg = 0; 39810bcbd6cSEtienne Carriere uint32_t bank = 0; 39910bcbd6cSEtienne Carriere uint32_t pin = 0; 40010bcbd6cSEtienne Carriere uint32_t mode = 0; 4014b5e93edSEtienne Carriere uint32_t alternate = 0; 402322cf9e3SEtienne Carriere uint32_t odata = 0; 4034b5e93edSEtienne Carriere bool opendrain = false; 4044b5e93edSEtienne Carriere 4054b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 4064b5e93edSEtienne Carriere cuint++; 4074b5e93edSEtienne Carriere 4084b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 4094b5e93edSEtienne Carriere 4104b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 4114b5e93edSEtienne Carriere 4124b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 4134b5e93edSEtienne Carriere 4144b5e93edSEtienne Carriere switch (mode) { 4154b5e93edSEtienne Carriere case 0: 4164b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 4174b5e93edSEtienne Carriere break; 4184b5e93edSEtienne Carriere case 1: 4194b5e93edSEtienne Carriere case 2: 4204b5e93edSEtienne Carriere case 3: 4214b5e93edSEtienne Carriere case 4: 4224b5e93edSEtienne Carriere case 5: 4234b5e93edSEtienne Carriere case 6: 4244b5e93edSEtienne Carriere case 7: 4254b5e93edSEtienne Carriere case 8: 4264b5e93edSEtienne Carriere case 9: 4274b5e93edSEtienne Carriere case 10: 4284b5e93edSEtienne Carriere case 11: 4294b5e93edSEtienne Carriere case 12: 4304b5e93edSEtienne Carriere case 13: 4314b5e93edSEtienne Carriere case 14: 4324b5e93edSEtienne Carriere case 15: 4334b5e93edSEtienne Carriere case 16: 4344b5e93edSEtienne Carriere alternate = mode - 1U; 4354b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 4364b5e93edSEtienne Carriere break; 4374b5e93edSEtienne Carriere case 17: 4384b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 4394b5e93edSEtienne Carriere break; 4404b5e93edSEtienne Carriere default: 4414b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 4424b5e93edSEtienne Carriere break; 4434b5e93edSEtienne Carriere } 4444b5e93edSEtienne Carriere 4454b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 4464b5e93edSEtienne Carriere opendrain = true; 4474b5e93edSEtienne Carriere 448322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 449322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 450322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 451322cf9e3SEtienne Carriere odata = 1; 452322cf9e3SEtienne Carriere } 453322cf9e3SEtienne Carriere 454322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 455322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 456322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 457322cf9e3SEtienne Carriere odata = 0; 458322cf9e3SEtienne Carriere } 459322cf9e3SEtienne Carriere 4604b5e93edSEtienne Carriere /* Check GPIO bank clock/base address against platform */ 4614b5e93edSEtienne Carriere ckeck_gpio_bank(fdt, bank, pinctrl_node); 4624b5e93edSEtienne Carriere 4634b5e93edSEtienne Carriere if (found < count) { 4644b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 4654b5e93edSEtienne Carriere 4664b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 4674b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 4684b5e93edSEtienne Carriere ref->active_cfg.mode = mode; 4694b5e93edSEtienne Carriere ref->active_cfg.otype = opendrain ? 1 : 0; 4704b5e93edSEtienne Carriere ref->active_cfg.ospeed = speed; 4714b5e93edSEtienne Carriere ref->active_cfg.pupd = pull; 472322cf9e3SEtienne Carriere ref->active_cfg.od = odata; 4734b5e93edSEtienne Carriere ref->active_cfg.af = alternate; 4744b5e93edSEtienne Carriere /* Default to analog mode for standby state */ 4754b5e93edSEtienne Carriere ref->standby_cfg.mode = GPIO_MODE_ANALOG; 4764b5e93edSEtienne Carriere ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL; 4774b5e93edSEtienne Carriere } 4784b5e93edSEtienne Carriere 4794b5e93edSEtienne Carriere found++; 4804b5e93edSEtienne Carriere } 4814b5e93edSEtienne Carriere 4824b5e93edSEtienne Carriere return (int)found; 4834b5e93edSEtienne Carriere } 4844b5e93edSEtienne Carriere 485420a32c5SEtienne Carriere static struct gpio *stm32_gpio_get_dt(struct dt_pargs *pargs, 486420a32c5SEtienne Carriere void *data, TEE_Result *res) 487420a32c5SEtienne Carriere { 488420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 489420a32c5SEtienne Carriere struct gpio *gpio = NULL; 490420a32c5SEtienne Carriere unsigned int shift_1b = 0; 491420a32c5SEtienne Carriere unsigned int shift_2b = 0; 492420a32c5SEtienne Carriere uint32_t exceptions = 0; 493420a32c5SEtienne Carriere uint32_t otype = 0; 494420a32c5SEtienne Carriere uint32_t pupd = 0; 495420a32c5SEtienne Carriere uint32_t mode = 0; 496420a32c5SEtienne Carriere 497420a32c5SEtienne Carriere gpio = gpio_dt_alloc_pin(pargs, res); 498420a32c5SEtienne Carriere if (*res) 499420a32c5SEtienne Carriere return NULL; 500420a32c5SEtienne Carriere 501420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 502420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 503420a32c5SEtienne Carriere free(gpio); 504420a32c5SEtienne Carriere return NULL; 505420a32c5SEtienne Carriere } 506420a32c5SEtienne Carriere 507420a32c5SEtienne Carriere shift_1b = gpio->pin; 508420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 509420a32c5SEtienne Carriere 510420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 511420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 512420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 513420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 514420a32c5SEtienne Carriere else 515420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 516420a32c5SEtienne Carriere 517420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 518420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 519420a32c5SEtienne Carriere else 520420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 521420a32c5SEtienne Carriere 522420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 523420a32c5SEtienne Carriere panic(); 524420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 525420a32c5SEtienne Carriere 526420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 527420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 528420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 529420a32c5SEtienne Carriere 530420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 531420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 532420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 533420a32c5SEtienne Carriere 534420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 535420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 536420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 537420a32c5SEtienne Carriere 538420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 539420a32c5SEtienne Carriere clk_disable(bank->clock); 540420a32c5SEtienne Carriere 541420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 542420a32c5SEtienne Carriere 543420a32c5SEtienne Carriere *res = TEE_SUCCESS; 544420a32c5SEtienne Carriere 545420a32c5SEtienne Carriere return gpio; 546420a32c5SEtienne Carriere } 547420a32c5SEtienne Carriere 5489818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 5499818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 5509818a481SEtienne Carriere { 5519818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 5529818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5539818a481SEtienne Carriere int len = 0; 5549818a481SEtienne Carriere 5559818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 5569818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 5579818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 5589818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 5599818a481SEtienne Carriere 5609818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 5619818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 5629818a481SEtienne Carriere panic("Wrong st,bank-name property"); 5639818a481SEtienne Carriere 5649818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 5659818a481SEtienne Carriere } 5669818a481SEtienne Carriere 5679818a481SEtienne Carriere /* 5689818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 5699818a481SEtienne Carriere * registered in the GPIO bank link. 5709818a481SEtienne Carriere */ 5719818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 5729818a481SEtienne Carriere { 5739818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 5749818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5759818a481SEtienne Carriere 5769818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 5779818a481SEtienne Carriere if (bank->bank_id == bank_id) 5789818a481SEtienne Carriere return true; 5799818a481SEtienne Carriere 5809818a481SEtienne Carriere return false; 5819818a481SEtienne Carriere } 5829818a481SEtienne Carriere 5839818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 5849818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 5859818a481SEtienne Carriere const void *compat_data __unused, 5869818a481SEtienne Carriere int range_offset, 5879818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 5889818a481SEtienne Carriere { 5899818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 5909818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5919818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5929818a481SEtienne Carriere struct io_pa_va pa_va = { }; 5939818a481SEtienne Carriere struct clk *clk = NULL; 5949818a481SEtienne Carriere size_t blen = 0; 5959818a481SEtienne Carriere paddr_t pa = 0; 5969818a481SEtienne Carriere int len = 0; 5979818a481SEtienne Carriere int i = 0; 5989818a481SEtienne Carriere 5999818a481SEtienne Carriere assert(out_bank); 6009818a481SEtienne Carriere 6019818a481SEtienne Carriere /* Probe deferrable devices first */ 6029818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 6039818a481SEtienne Carriere if (res) 6049818a481SEtienne Carriere return res; 6059818a481SEtienne Carriere 6069818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 6079818a481SEtienne Carriere if (!bank) 6089818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 6099818a481SEtienne Carriere 6109818a481SEtienne Carriere /* 6119818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 6129818a481SEtienne Carriere * but consider also the "ranges" translation property 6139818a481SEtienne Carriere */ 6149818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 6159818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 6169818a481SEtienne Carriere panic("missing reg property"); 6179818a481SEtienne Carriere 6189818a481SEtienne Carriere pa_va.pa = pa + range_offset; 6199818a481SEtienne Carriere 6209818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 6219818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 6229818a481SEtienne Carriere panic("missing reg size property"); 6239818a481SEtienne Carriere 6249818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 6259818a481SEtienne Carriere bank->base = io_pa_or_va_secure(&pa_va, blen); 6269818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 6279818a481SEtienne Carriere bank->clock = clk; 628420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 6299818a481SEtienne Carriere 6309818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 6319818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 6329818a481SEtienne Carriere len /= sizeof(*cuint); 6339818a481SEtienne Carriere if (len % 4) 6349818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 6359818a481SEtienne Carriere 6369818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 6379818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 6389818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 6399818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 6409818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 6419818a481SEtienne Carriere cuint += 4; 6429818a481SEtienne Carriere } 6439818a481SEtienne Carriere 6449818a481SEtienne Carriere *out_bank = bank; 6459818a481SEtienne Carriere return TEE_SUCCESS; 6469818a481SEtienne Carriere } 6479818a481SEtienne Carriere 6489818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */ 6490e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 6509818a481SEtienne Carriere const void *compat_data) 6519818a481SEtienne Carriere { 6529818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 6539818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6549818a481SEtienne Carriere int range_offs = 0; 6559818a481SEtienne Carriere int b_node = 0; 6569818a481SEtienne Carriere int len = 0; 6579818a481SEtienne Carriere 6589818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 6599818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 6609818a481SEtienne Carriere if (!cuint) 6619818a481SEtienne Carriere panic("missing ranges property"); 6629818a481SEtienne Carriere 6639818a481SEtienne Carriere len /= sizeof(*cuint); 6649818a481SEtienne Carriere if (len == 3) 6659818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 6669818a481SEtienne Carriere 6679818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 6689818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 6699818a481SEtienne Carriere if (cuint) { 6709818a481SEtienne Carriere /* 6719818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 6729818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 6739818a481SEtienne Carriere * bank list. 6749818a481SEtienne Carriere */ 6759818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6769818a481SEtienne Carriere 6779818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 6789818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 6799818a481SEtienne Carriere continue; 6809818a481SEtienne Carriere 6819818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 6829818a481SEtienne Carriere range_offs, &bank); 6839818a481SEtienne Carriere if (res) 6849818a481SEtienne Carriere return res; 6859818a481SEtienne Carriere 686420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 687420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 688420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 689420a32c5SEtienne Carriere if (res) 690420a32c5SEtienne Carriere panic(); 691420a32c5SEtienne Carriere 6929818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 6939818a481SEtienne Carriere } else { 6949818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 6959818a481SEtienne Carriere panic(); 6969818a481SEtienne Carriere } 6979818a481SEtienne Carriere } 6989818a481SEtienne Carriere 6999818a481SEtienne Carriere return TEE_SUCCESS; 7009818a481SEtienne Carriere } 7019818a481SEtienne Carriere 7024b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node, 7034b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 7044b5e93edSEtienne Carriere { 70510bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 70610bcbd6cSEtienne Carriere int lenp = 0; 70710bcbd6cSEtienne Carriere int i = 0; 7084b5e93edSEtienne Carriere size_t found = 0; 7094b5e93edSEtienne Carriere 7104b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp); 7114b5e93edSEtienne Carriere if (!cuint) 7124b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7134b5e93edSEtienne Carriere 7144b5e93edSEtienne Carriere for (i = 0; i < (lenp / 4); i++) { 71510bcbd6cSEtienne Carriere int node = 0; 71610bcbd6cSEtienne Carriere int subnode = 0; 7174b5e93edSEtienne Carriere 7184b5e93edSEtienne Carriere node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 7194b5e93edSEtienne Carriere if (node < 0) 7204b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7214b5e93edSEtienne Carriere 7224b5e93edSEtienne Carriere fdt_for_each_subnode(subnode, fdt, node) { 72310bcbd6cSEtienne Carriere size_t n = 0; 72410bcbd6cSEtienne Carriere int rc = 0; 7254b5e93edSEtienne Carriere 7264b5e93edSEtienne Carriere if (count > found) 7274b5e93edSEtienne Carriere n = count - found; 7284b5e93edSEtienne Carriere else 7294b5e93edSEtienne Carriere n = 0; 7304b5e93edSEtienne Carriere 7314b5e93edSEtienne Carriere rc = get_pinctrl_from_fdt(fdt, subnode, 7324b5e93edSEtienne Carriere &pinctrl[found], n); 7334b5e93edSEtienne Carriere if (rc < 0) 7344b5e93edSEtienne Carriere return rc; 7354b5e93edSEtienne Carriere 7364b5e93edSEtienne Carriere found += (size_t)rc; 7374b5e93edSEtienne Carriere } 7384b5e93edSEtienne Carriere 7394b5e93edSEtienne Carriere cuint++; 7404b5e93edSEtienne Carriere } 7414b5e93edSEtienne Carriere 7424b5e93edSEtienne Carriere return (int)found; 7434b5e93edSEtienne Carriere } 744a3104caaSEtienne Carriere 745a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank) 746a3104caaSEtienne Carriere { 747a3104caaSEtienne Carriere int node = 0; 748a3104caaSEtienne Carriere const fdt32_t *cuint = NULL; 749a3104caaSEtienne Carriere 750a3104caaSEtienne Carriere fdt_for_each_subnode(node, fdt, pinctrl_node) { 751a3104caaSEtienne Carriere if (!fdt_getprop(fdt, node, "gpio-controller", NULL)) 752a3104caaSEtienne Carriere continue; 753a3104caaSEtienne Carriere 754a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "reg", NULL); 755a3104caaSEtienne Carriere if (!cuint) 756a3104caaSEtienne Carriere continue; 757a3104caaSEtienne Carriere 758a3104caaSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 759a3104caaSEtienne Carriere continue; 760a3104caaSEtienne Carriere 761a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "ngpios", NULL); 762a3104caaSEtienne Carriere if (!cuint) 763a3104caaSEtienne Carriere panic(); 764a3104caaSEtienne Carriere 765a3104caaSEtienne Carriere return (int)fdt32_to_cpu(*cuint); 766a3104caaSEtienne Carriere } 767a3104caaSEtienne Carriere 768a3104caaSEtienne Carriere return -1; 769a3104caaSEtienne Carriere } 7704b5e93edSEtienne Carriere 771077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 772077d486eSEtienne Carriere bool secure) 7734b5e93edSEtienne Carriere { 774077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 77598dfcedaSEtienne Carriere uint32_t exceptions = 0; 7764b5e93edSEtienne Carriere 777077d486eSEtienne Carriere if (clk_enable(bank->clock)) 778077d486eSEtienne Carriere panic(); 77998dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 7804b5e93edSEtienne Carriere 7814b5e93edSEtienne Carriere if (secure) 782077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7834b5e93edSEtienne Carriere else 784077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7854b5e93edSEtienne Carriere 786c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 78798dfcedaSEtienne Carriere clk_disable(bank->clock); 7884b5e93edSEtienne Carriere } 7890e0435e2SEtienne Carriere 7900e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 7910e0435e2SEtienne Carriere const void *compat_data) 7920e0435e2SEtienne Carriere { 7930e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 7940e0435e2SEtienne Carriere return dt_stm32_gpio_pinctrl(fdt, node, compat_data); 7950e0435e2SEtienne Carriere } 7960e0435e2SEtienne Carriere 7970e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 7980e0435e2SEtienne Carriere { .compatible = "st,stm32mp135-pinctrl" }, 7990e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-pinctrl" }, 8000e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-z-pinctrl" }, 8010e0435e2SEtienne Carriere { } 8020e0435e2SEtienne Carriere }; 8030e0435e2SEtienne Carriere 8040e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 8050e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 8060e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 8070e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 8080e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 8090e0435e2SEtienne Carriere }; 810