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> 9*69715ce9SEtienne Carriere #include <compiler.h> 1097391ffbSEtienne Carriere #include <drivers/clk.h> 1197391ffbSEtienne Carriere #include <drivers/clk_dt.h> 12420a32c5SEtienne Carriere #include <drivers/gpio.h> 13b38386fbSEtienne Carriere #include <drivers/pinctrl.h> 144b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h> 154b5e93edSEtienne Carriere #include <io.h> 164b5e93edSEtienne Carriere #include <kernel/dt.h> 1765401337SJens Wiklander #include <kernel/boot.h> 184b5e93edSEtienne Carriere #include <kernel/panic.h> 194b5e93edSEtienne Carriere #include <kernel/spinlock.h> 20a2fc83d1SJerome Forissier #include <libfdt.h> 214b5e93edSEtienne Carriere #include <mm/core_memprot.h> 224b5e93edSEtienne Carriere #include <stdbool.h> 23*69715ce9SEtienne Carriere #include <stdint.h> 244b5e93edSEtienne Carriere #include <stm32_util.h> 259818a481SEtienne Carriere #include <sys/queue.h> 264b5e93edSEtienne Carriere #include <trace.h> 274b5e93edSEtienne Carriere #include <util.h> 284b5e93edSEtienne Carriere 291001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 301001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 311001585eSEtienne Carriere #endif 321001585eSEtienne Carriere 334b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 344b5e93edSEtienne Carriere 354b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET 0x00 364b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET 0x04 374b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET 0x08 384b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET 0x0c 394b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET 0x10 404b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET 0x14 414b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET 0x18 424b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET 0x20 434b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET 0x24 444b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET 0x30 454b5e93edSEtienne Carriere 464b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT 0x8 474b5e93edSEtienne Carriere 484b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 494b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 504b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 51729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 524b5e93edSEtienne Carriere 534b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT 12 544b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 554b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT 8 564b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 574b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 584b5e93edSEtienne Carriere 599818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 609818a481SEtienne Carriere 61*69715ce9SEtienne Carriere #define GPIO_MODE_INPUT U(0x0) 62*69715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT U(0x1) 63*69715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE U(0x2) 64*69715ce9SEtienne Carriere #define GPIO_MODE_ANALOG U(0x3) 65*69715ce9SEtienne Carriere 66*69715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL U(0x0) 67*69715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN U(0x1) 68*69715ce9SEtienne Carriere 69*69715ce9SEtienne Carriere #define GPIO_OSPEED_LOW U(0x0) 70*69715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM U(0x1) 71*69715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH U(0x2) 72*69715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH U(0x3) 73*69715ce9SEtienne Carriere 74*69715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL U(0x0) 75*69715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP U(0x1) 76*69715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN U(0x2) 77*69715ce9SEtienne Carriere 78*69715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW U(0x0) 79*69715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH U(0x1) 80*69715ce9SEtienne Carriere 81*69715ce9SEtienne Carriere /* 82*69715ce9SEtienne Carriere * GPIO configuration description structured as single 16bit word 83*69715ce9SEtienne Carriere * for efficient save/restore when GPIO pin suspends or resumes. 84*69715ce9SEtienne Carriere * 85*69715ce9SEtienne Carriere * @mode: One of GPIO_MODE_* 86*69715ce9SEtienne Carriere * @otype: One of GPIO_OTYPE_* 87*69715ce9SEtienne Carriere * @ospeed: One of GPIO_OSPEED_* 88*69715ce9SEtienne Carriere * @pupd: One of GPIO_PUPD_* 89*69715ce9SEtienne Carriere * @od: One of GPIO_OD_* 90*69715ce9SEtienne Carriere * @af: Alternate function numerical ID between 0 and 15 91*69715ce9SEtienne Carriere */ 92*69715ce9SEtienne Carriere struct gpio_cfg { 93*69715ce9SEtienne Carriere uint16_t mode: 2; 94*69715ce9SEtienne Carriere uint16_t otype: 1; 95*69715ce9SEtienne Carriere uint16_t ospeed: 2; 96*69715ce9SEtienne Carriere uint16_t pupd: 2; 97*69715ce9SEtienne Carriere uint16_t od: 1; 98*69715ce9SEtienne Carriere uint16_t af: 4; 99*69715ce9SEtienne Carriere }; 100*69715ce9SEtienne Carriere 101*69715ce9SEtienne Carriere /* 102*69715ce9SEtienne Carriere * Description of a pin and its muxing 103*69715ce9SEtienne Carriere * 104*69715ce9SEtienne Carriere * @bank: GPIO bank identifier as assigned by the platform 105*69715ce9SEtienne Carriere * @pin: Pin number in the GPIO bank 106*69715ce9SEtienne Carriere * @cfg: Pin configuration 107*69715ce9SEtienne Carriere */ 108*69715ce9SEtienne Carriere struct stm32_pinctrl { 109*69715ce9SEtienne Carriere uint8_t bank; 110*69715ce9SEtienne Carriere uint8_t pin; 111*69715ce9SEtienne Carriere struct gpio_cfg cfg; 112*69715ce9SEtienne Carriere }; 113*69715ce9SEtienne Carriere 114b38386fbSEtienne Carriere /* 115b38386fbSEtienne Carriere * struct stm32_pinctrl_array - Array of pins in a pin control state 116b38386fbSEtienne Carriere * @count: Number of cells in @pinctrl 117b38386fbSEtienne Carriere * @pinctrl: Pin control configuration 118b38386fbSEtienne Carriere */ 119b38386fbSEtienne Carriere struct stm32_pinctrl_array { 120b38386fbSEtienne Carriere size_t count; 121b38386fbSEtienne Carriere struct stm32_pinctrl pinctrl[]; 122b38386fbSEtienne Carriere }; 123b38386fbSEtienne Carriere 1249818a481SEtienne Carriere /** 1259818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 1269818a481SEtienne Carriere * 1279818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 1289818a481SEtienne Carriere * @clock: clock identifier. 129420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 1309818a481SEtienne Carriere * @ngpios: number of GPIOs. 1319818a481SEtienne Carriere * @bank_id: Id of the bank. 1329818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 1339818a481SEtienne Carriere * @sec_support: True if bank supports pin security protection, otherwise false 1349818a481SEtienne Carriere * @seccfgr: Secure configuration register value. 1359818a481SEtienne Carriere * @link: Link in bank list 1369818a481SEtienne Carriere */ 1379818a481SEtienne Carriere struct stm32_gpio_bank { 1389818a481SEtienne Carriere vaddr_t base; 1399818a481SEtienne Carriere struct clk *clock; 140420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 1419818a481SEtienne Carriere unsigned int ngpios; 1429818a481SEtienne Carriere unsigned int bank_id; 1439818a481SEtienne Carriere unsigned int lock; 1449818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 1459818a481SEtienne Carriere }; 1469818a481SEtienne Carriere 1474b5e93edSEtienne Carriere static unsigned int gpio_lock; 1484b5e93edSEtienne Carriere 1499818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 1509818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 1519818a481SEtienne Carriere 152420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 153420a32c5SEtienne Carriere 154420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 155420a32c5SEtienne Carriere { 156420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 157420a32c5SEtienne Carriere } 158420a32c5SEtienne Carriere 159420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 160420a32c5SEtienne Carriere unsigned int gpio_pin) 161420a32c5SEtienne Carriere { 162420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 163420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 164420a32c5SEtienne Carriere unsigned int reg_offset = 0; 165420a32c5SEtienne Carriere unsigned int mode = 0; 166420a32c5SEtienne Carriere 167420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1682fd102ebSEtienne Carriere 1692fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1702fd102ebSEtienne Carriere panic(); 171420a32c5SEtienne Carriere 172420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 173420a32c5SEtienne Carriere GPIO_MODE_MASK; 174420a32c5SEtienne Carriere 175420a32c5SEtienne Carriere switch (mode) { 176420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 177420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 178420a32c5SEtienne Carriere break; 179420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 180420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 181420a32c5SEtienne Carriere break; 182420a32c5SEtienne Carriere default: 183420a32c5SEtienne Carriere panic(); 184420a32c5SEtienne Carriere } 185420a32c5SEtienne Carriere 186420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 187420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 188420a32c5SEtienne Carriere else 189420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 190420a32c5SEtienne Carriere 191420a32c5SEtienne Carriere clk_disable(bank->clock); 192420a32c5SEtienne Carriere 193420a32c5SEtienne Carriere return level; 194420a32c5SEtienne Carriere } 195420a32c5SEtienne Carriere 196420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 197420a32c5SEtienne Carriere enum gpio_level level) 198420a32c5SEtienne Carriere { 199420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 200420a32c5SEtienne Carriere 201420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2022fd102ebSEtienne Carriere 2032fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2042fd102ebSEtienne Carriere panic(); 205420a32c5SEtienne Carriere 206420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 207420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 208420a32c5SEtienne Carriere 209420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 210420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 211420a32c5SEtienne Carriere else 212420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 213420a32c5SEtienne Carriere 214420a32c5SEtienne Carriere clk_disable(bank->clock); 215420a32c5SEtienne Carriere } 216420a32c5SEtienne Carriere 217420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 218420a32c5SEtienne Carriere unsigned int gpio_pin) 219420a32c5SEtienne Carriere { 220420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 221420a32c5SEtienne Carriere uint32_t mode = 0; 222420a32c5SEtienne Carriere 223420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2242fd102ebSEtienne Carriere 2252fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2262fd102ebSEtienne Carriere panic(); 227420a32c5SEtienne Carriere 228420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 229420a32c5SEtienne Carriere GPIO_MODE_MASK; 230420a32c5SEtienne Carriere 231420a32c5SEtienne Carriere clk_disable(bank->clock); 232420a32c5SEtienne Carriere 233420a32c5SEtienne Carriere switch (mode) { 234420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 235420a32c5SEtienne Carriere return GPIO_DIR_IN; 236420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 237420a32c5SEtienne Carriere return GPIO_DIR_OUT; 238420a32c5SEtienne Carriere default: 239420a32c5SEtienne Carriere panic(); 240420a32c5SEtienne Carriere } 241420a32c5SEtienne Carriere } 242420a32c5SEtienne Carriere 243420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 244420a32c5SEtienne Carriere unsigned int gpio_pin, 245420a32c5SEtienne Carriere enum gpio_dir direction) 246420a32c5SEtienne Carriere { 247420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 248420a32c5SEtienne Carriere uint32_t exceptions = 0; 249420a32c5SEtienne Carriere uint32_t mode = 0; 250420a32c5SEtienne Carriere 251420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 252420a32c5SEtienne Carriere 253420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 254420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 255420a32c5SEtienne Carriere else 256420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 257420a32c5SEtienne Carriere 2582fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2592fd102ebSEtienne Carriere panic(); 260420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 261420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 262420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 263420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 264420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 265420a32c5SEtienne Carriere clk_disable(bank->clock); 266420a32c5SEtienne Carriere } 267420a32c5SEtienne Carriere 268420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 269420a32c5SEtienne Carriere struct gpio *gpio) 270420a32c5SEtienne Carriere { 271420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 272420a32c5SEtienne Carriere free(gpio); 273420a32c5SEtienne Carriere } 274420a32c5SEtienne Carriere 275420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 276420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 277420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 278420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 279420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 280420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 281420a32c5SEtienne Carriere }; 282420a32c5SEtienne Carriere 283420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 284420a32c5SEtienne Carriere { 285420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 286420a32c5SEtienne Carriere } 287420a32c5SEtienne Carriere 288077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 2894b5e93edSEtienne Carriere { 290077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 2914b5e93edSEtienne Carriere 292077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 293077d486eSEtienne Carriere if (bank_id == bank->bank_id) 294077d486eSEtienne Carriere return bank; 295077d486eSEtienne Carriere 296077d486eSEtienne Carriere panic(); 297077d486eSEtienne Carriere } 298077d486eSEtienne Carriere 299077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 300b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin, 301b38386fbSEtienne Carriere struct gpio_cfg *cfg) 302077d486eSEtienne Carriere { 303077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 304077d486eSEtienne Carriere 305077d486eSEtienne Carriere if (clk_enable(bank->clock)) 306077d486eSEtienne Carriere panic(); 3074b5e93edSEtienne Carriere 3084b5e93edSEtienne Carriere /* 3094b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 3104b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 3114b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 3124b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 3134b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 3144b5e93edSEtienne Carriere */ 315077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 3164b5e93edSEtienne Carriere GPIO_MODE_MASK; 3174b5e93edSEtienne Carriere 318077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 3194b5e93edSEtienne Carriere 320077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 321077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 3224b5e93edSEtienne Carriere 323077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 3244b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 3254b5e93edSEtienne Carriere 326077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 3274b5e93edSEtienne Carriere 3284b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 329077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 330077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 3314b5e93edSEtienne Carriere else 332077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 3334b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 3344b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 3354b5e93edSEtienne Carriere 336077d486eSEtienne Carriere clk_disable(bank->clock); 3374b5e93edSEtienne Carriere } 3384b5e93edSEtienne Carriere 3394b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 340077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 3414b5e93edSEtienne Carriere { 342077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 34398dfcedaSEtienne Carriere uint32_t exceptions = 0; 3444b5e93edSEtienne Carriere 345077d486eSEtienne Carriere if (clk_enable(bank->clock)) 346077d486eSEtienne Carriere panic(); 34798dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 3484b5e93edSEtienne Carriere 3494b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 350077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 351bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 352bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 3534b5e93edSEtienne Carriere 3544b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 355077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 356bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 3574b5e93edSEtienne Carriere 3584b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 359077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 360bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 361bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 3624b5e93edSEtienne Carriere 3634b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 364077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 365bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 3664b5e93edSEtienne Carriere 3674b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 3684b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 369077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 370bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 371bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 3724b5e93edSEtienne Carriere } else { 3734b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 3744b5e93edSEtienne Carriere 375077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 376bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 377bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 3784b5e93edSEtienne Carriere } 3794b5e93edSEtienne Carriere 3804b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 381077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 3824b5e93edSEtienne Carriere 383c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 38498dfcedaSEtienne Carriere clk_disable(bank->clock); 3854b5e93edSEtienne Carriere } 3864b5e93edSEtienne Carriere 3874b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 388b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node, 3894b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 3904b5e93edSEtienne Carriere { 391b38386fbSEtienne Carriere const fdt32_t *cuint = NULL; 392b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL; 39310bcbd6cSEtienne Carriere int len = 0; 39410bcbd6cSEtienne Carriere uint32_t i = 0; 3954b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 3964b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 3974b5e93edSEtienne Carriere size_t found = 0; 3984b5e93edSEtienne Carriere 3994b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 4004b5e93edSEtienne Carriere if (!cuint) 4014b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 4024b5e93edSEtienne Carriere 4034b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 4044b5e93edSEtienne Carriere if (slewrate) 4054b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 4064b5e93edSEtienne Carriere 4074b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 4084b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 4094b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 4104b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 4114b5e93edSEtienne Carriere 4124b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 41310bcbd6cSEtienne Carriere uint32_t pincfg = 0; 41410bcbd6cSEtienne Carriere uint32_t bank = 0; 41510bcbd6cSEtienne Carriere uint32_t pin = 0; 41610bcbd6cSEtienne Carriere uint32_t mode = 0; 4174b5e93edSEtienne Carriere uint32_t alternate = 0; 418322cf9e3SEtienne Carriere uint32_t odata = 0; 4194b5e93edSEtienne Carriere bool opendrain = false; 4204b5e93edSEtienne Carriere 4214b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 4224b5e93edSEtienne Carriere cuint++; 4234b5e93edSEtienne Carriere 4244b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 4254b5e93edSEtienne Carriere 4264b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 4274b5e93edSEtienne Carriere 4284b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 4294b5e93edSEtienne Carriere 4304b5e93edSEtienne Carriere switch (mode) { 4314b5e93edSEtienne Carriere case 0: 4324b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 4334b5e93edSEtienne Carriere break; 4344b5e93edSEtienne Carriere case 1: 4354b5e93edSEtienne Carriere case 2: 4364b5e93edSEtienne Carriere case 3: 4374b5e93edSEtienne Carriere case 4: 4384b5e93edSEtienne Carriere case 5: 4394b5e93edSEtienne Carriere case 6: 4404b5e93edSEtienne Carriere case 7: 4414b5e93edSEtienne Carriere case 8: 4424b5e93edSEtienne Carriere case 9: 4434b5e93edSEtienne Carriere case 10: 4444b5e93edSEtienne Carriere case 11: 4454b5e93edSEtienne Carriere case 12: 4464b5e93edSEtienne Carriere case 13: 4474b5e93edSEtienne Carriere case 14: 4484b5e93edSEtienne Carriere case 15: 4494b5e93edSEtienne Carriere case 16: 4504b5e93edSEtienne Carriere alternate = mode - 1U; 4514b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 4524b5e93edSEtienne Carriere break; 4534b5e93edSEtienne Carriere case 17: 4544b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 4554b5e93edSEtienne Carriere break; 4564b5e93edSEtienne Carriere default: 4574b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 4584b5e93edSEtienne Carriere break; 4594b5e93edSEtienne Carriere } 4604b5e93edSEtienne Carriere 4614b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 4624b5e93edSEtienne Carriere opendrain = true; 4634b5e93edSEtienne Carriere 464322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 465322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 466322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 467322cf9e3SEtienne Carriere odata = 1; 468322cf9e3SEtienne Carriere } 469322cf9e3SEtienne Carriere 470322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 471322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 472322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 473322cf9e3SEtienne Carriere odata = 0; 474322cf9e3SEtienne Carriere } 475322cf9e3SEtienne Carriere 4764b5e93edSEtienne Carriere if (found < count) { 4774b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 4784b5e93edSEtienne Carriere 4794b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 4804b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 481b38386fbSEtienne Carriere ref->cfg.mode = mode; 482b38386fbSEtienne Carriere if (opendrain) 483b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN; 484b38386fbSEtienne Carriere else 485b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL; 486b38386fbSEtienne Carriere ref->cfg.ospeed = speed; 487b38386fbSEtienne Carriere ref->cfg.pupd = pull; 488b38386fbSEtienne Carriere ref->cfg.od = odata; 489b38386fbSEtienne Carriere ref->cfg.af = alternate; 4904b5e93edSEtienne Carriere } 4914b5e93edSEtienne Carriere 4924b5e93edSEtienne Carriere found++; 4934b5e93edSEtienne Carriere } 4944b5e93edSEtienne Carriere 4954b5e93edSEtienne Carriere return (int)found; 4964b5e93edSEtienne Carriere } 4974b5e93edSEtienne Carriere 498b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data, 499b357d34fSEtienne Carriere struct gpio **out_gpio) 500420a32c5SEtienne Carriere { 501b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 502420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 503420a32c5SEtienne Carriere struct gpio *gpio = NULL; 504420a32c5SEtienne Carriere unsigned int shift_1b = 0; 505420a32c5SEtienne Carriere unsigned int shift_2b = 0; 506420a32c5SEtienne Carriere uint32_t exceptions = 0; 507420a32c5SEtienne Carriere uint32_t otype = 0; 508420a32c5SEtienne Carriere uint32_t pupd = 0; 509420a32c5SEtienne Carriere uint32_t mode = 0; 510420a32c5SEtienne Carriere 511b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio); 512b357d34fSEtienne Carriere if (res) 513b357d34fSEtienne Carriere return res; 514420a32c5SEtienne Carriere 515420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 516420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 517420a32c5SEtienne Carriere free(gpio); 518b357d34fSEtienne Carriere return TEE_ERROR_GENERIC; 519420a32c5SEtienne Carriere } 520420a32c5SEtienne Carriere 521420a32c5SEtienne Carriere shift_1b = gpio->pin; 522420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 523420a32c5SEtienne Carriere 524420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 525420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 526420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 527420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 528420a32c5SEtienne Carriere else 529420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 530420a32c5SEtienne Carriere 531420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 532420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 533420a32c5SEtienne Carriere else 534420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 535420a32c5SEtienne Carriere 536420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 537420a32c5SEtienne Carriere panic(); 538420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 539420a32c5SEtienne Carriere 540420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 541420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 542420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 543420a32c5SEtienne Carriere 544420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 545420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 546420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 547420a32c5SEtienne Carriere 548420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 549420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 550420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 551420a32c5SEtienne Carriere 552420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 553420a32c5SEtienne Carriere clk_disable(bank->clock); 554420a32c5SEtienne Carriere 555420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 556420a32c5SEtienne Carriere 557b357d34fSEtienne Carriere *out_gpio = gpio; 558420a32c5SEtienne Carriere 559b357d34fSEtienne Carriere return TEE_SUCCESS; 560420a32c5SEtienne Carriere } 561420a32c5SEtienne Carriere 5629818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 5639818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 5649818a481SEtienne Carriere { 5659818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 5669818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5679818a481SEtienne Carriere int len = 0; 5689818a481SEtienne Carriere 5699818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 5709818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 5719818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 5729818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 5739818a481SEtienne Carriere 5749818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 5759818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 5769818a481SEtienne Carriere panic("Wrong st,bank-name property"); 5779818a481SEtienne Carriere 5789818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 5799818a481SEtienne Carriere } 5809818a481SEtienne Carriere 5819818a481SEtienne Carriere /* 5829818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 5839818a481SEtienne Carriere * registered in the GPIO bank link. 5849818a481SEtienne Carriere */ 5859818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 5869818a481SEtienne Carriere { 5879818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 5889818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5899818a481SEtienne Carriere 5909818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 5919818a481SEtienne Carriere if (bank->bank_id == bank_id) 5929818a481SEtienne Carriere return true; 5939818a481SEtienne Carriere 5949818a481SEtienne Carriere return false; 5959818a481SEtienne Carriere } 5969818a481SEtienne Carriere 5979818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 5989818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 5999818a481SEtienne Carriere const void *compat_data __unused, 6009818a481SEtienne Carriere int range_offset, 6019818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 6029818a481SEtienne Carriere { 6039818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 6049818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6059818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6069818a481SEtienne Carriere struct io_pa_va pa_va = { }; 6079818a481SEtienne Carriere struct clk *clk = NULL; 6089818a481SEtienne Carriere size_t blen = 0; 6099818a481SEtienne Carriere paddr_t pa = 0; 6109818a481SEtienne Carriere int len = 0; 6119818a481SEtienne Carriere int i = 0; 6129818a481SEtienne Carriere 6139818a481SEtienne Carriere assert(out_bank); 6149818a481SEtienne Carriere 6159818a481SEtienne Carriere /* Probe deferrable devices first */ 6169818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 6179818a481SEtienne Carriere if (res) 6189818a481SEtienne Carriere return res; 6199818a481SEtienne Carriere 6209818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 6219818a481SEtienne Carriere if (!bank) 6229818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 6239818a481SEtienne Carriere 6249818a481SEtienne Carriere /* 6259818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 6269818a481SEtienne Carriere * but consider also the "ranges" translation property 6279818a481SEtienne Carriere */ 6289818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 6299818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 6309818a481SEtienne Carriere panic("missing reg property"); 6319818a481SEtienne Carriere 6329818a481SEtienne Carriere pa_va.pa = pa + range_offset; 6339818a481SEtienne Carriere 6349818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 6359818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 6369818a481SEtienne Carriere panic("missing reg size property"); 6379818a481SEtienne Carriere 6389818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 6399818a481SEtienne Carriere bank->base = io_pa_or_va_secure(&pa_va, blen); 6409818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 6419818a481SEtienne Carriere bank->clock = clk; 642420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 6439818a481SEtienne Carriere 6449818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 6459818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 6469818a481SEtienne Carriere len /= sizeof(*cuint); 6479818a481SEtienne Carriere if (len % 4) 6489818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 6499818a481SEtienne Carriere 6509818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 6519818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 6529818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 6539818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 6549818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 6559818a481SEtienne Carriere cuint += 4; 6569818a481SEtienne Carriere } 6579818a481SEtienne Carriere 6589818a481SEtienne Carriere *out_bank = bank; 6599818a481SEtienne Carriere return TEE_SUCCESS; 6609818a481SEtienne Carriere } 6619818a481SEtienne Carriere 662be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank) 663be53ee7bSEtienne Carriere { 664be53ee7bSEtienne Carriere unsigned int pin = 0; 665be53ee7bSEtienne Carriere 666be53ee7bSEtienne Carriere for (pin = 0; pin <= bank->ngpios; pin++) 667be53ee7bSEtienne Carriere stm32_gpio_set_secure_cfg(bank->bank_id, pin, false); 668be53ee7bSEtienne Carriere } 669be53ee7bSEtienne Carriere 6709818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */ 6710e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 6729818a481SEtienne Carriere const void *compat_data) 6739818a481SEtienne Carriere { 6749818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 6759818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6769818a481SEtienne Carriere int range_offs = 0; 6779818a481SEtienne Carriere int b_node = 0; 6789818a481SEtienne Carriere int len = 0; 6799818a481SEtienne Carriere 6809818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 6819818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 6829818a481SEtienne Carriere if (!cuint) 6839818a481SEtienne Carriere panic("missing ranges property"); 6849818a481SEtienne Carriere 6859818a481SEtienne Carriere len /= sizeof(*cuint); 6869818a481SEtienne Carriere if (len == 3) 6879818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 6889818a481SEtienne Carriere 6899818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 6909818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 6919818a481SEtienne Carriere if (cuint) { 6929818a481SEtienne Carriere /* 6939818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 6949818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 6959818a481SEtienne Carriere * bank list. 6969818a481SEtienne Carriere */ 6979818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6989818a481SEtienne Carriere 6999818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 7009818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 7019818a481SEtienne Carriere continue; 7029818a481SEtienne Carriere 7039818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 7049818a481SEtienne Carriere range_offs, &bank); 7059818a481SEtienne Carriere if (res) 7069818a481SEtienne Carriere return res; 7079818a481SEtienne Carriere 708420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 709420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 710420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 711420a32c5SEtienne Carriere if (res) 712420a32c5SEtienne Carriere panic(); 713420a32c5SEtienne Carriere 7149818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 715be53ee7bSEtienne Carriere 716be53ee7bSEtienne Carriere if (IS_ENABLED(CFG_STM32MP13)) 717be53ee7bSEtienne Carriere set_bank_gpio_non_secure(bank); 7189818a481SEtienne Carriere } else { 7199818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 7209818a481SEtienne Carriere panic(); 7219818a481SEtienne Carriere } 7229818a481SEtienne Carriere } 7239818a481SEtienne Carriere 7249818a481SEtienne Carriere return TEE_SUCCESS; 7259818a481SEtienne Carriere } 7269818a481SEtienne Carriere 727a3104caaSEtienne Carriere 728a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank) 729a3104caaSEtienne Carriere { 730a3104caaSEtienne Carriere int node = 0; 731a3104caaSEtienne Carriere const fdt32_t *cuint = NULL; 732a3104caaSEtienne Carriere 733a3104caaSEtienne Carriere fdt_for_each_subnode(node, fdt, pinctrl_node) { 734a3104caaSEtienne Carriere if (!fdt_getprop(fdt, node, "gpio-controller", NULL)) 735a3104caaSEtienne Carriere continue; 736a3104caaSEtienne Carriere 737a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "reg", NULL); 738a3104caaSEtienne Carriere if (!cuint) 739a3104caaSEtienne Carriere continue; 740a3104caaSEtienne Carriere 741a3104caaSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 742a3104caaSEtienne Carriere continue; 743a3104caaSEtienne Carriere 744a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "ngpios", NULL); 745a3104caaSEtienne Carriere if (!cuint) 746a3104caaSEtienne Carriere panic(); 747a3104caaSEtienne Carriere 748a3104caaSEtienne Carriere return (int)fdt32_to_cpu(*cuint); 749a3104caaSEtienne Carriere } 750a3104caaSEtienne Carriere 751a3104caaSEtienne Carriere return -1; 752a3104caaSEtienne Carriere } 7534b5e93edSEtienne Carriere 754077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 755077d486eSEtienne Carriere bool secure) 7564b5e93edSEtienne Carriere { 757077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 75898dfcedaSEtienne Carriere uint32_t exceptions = 0; 7594b5e93edSEtienne Carriere 760077d486eSEtienne Carriere if (clk_enable(bank->clock)) 761077d486eSEtienne Carriere panic(); 76298dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 7634b5e93edSEtienne Carriere 7644b5e93edSEtienne Carriere if (secure) 765077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7664b5e93edSEtienne Carriere else 767077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7684b5e93edSEtienne Carriere 769c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 77098dfcedaSEtienne Carriere clk_disable(bank->clock); 7714b5e93edSEtienne Carriere } 7720e0435e2SEtienne Carriere 773b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 774b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf) 775b38386fbSEtienne Carriere { 776b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv; 777b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl; 778b38386fbSEtienne Carriere size_t pin_count = ref->count; 779b38386fbSEtienne Carriere size_t n = 0; 780b38386fbSEtienne Carriere 781b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++) 782b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg); 783b38386fbSEtienne Carriere 784b38386fbSEtienne Carriere return TEE_SUCCESS; 785b38386fbSEtienne Carriere } 786b38386fbSEtienne Carriere 787b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf) 788b38386fbSEtienne Carriere { 789b38386fbSEtienne Carriere free(conf); 790b38386fbSEtienne Carriere } 791b38386fbSEtienne Carriere 792b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = { 793b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply, 794b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free, 795b38386fbSEtienne Carriere }; 796b38386fbSEtienne Carriere 797b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops); 798b38386fbSEtienne Carriere 79970ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl, 80070ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin, 80170ac0db5SEtienne Carriere unsigned int *count) 80270ac0db5SEtienne Carriere { 80370ac0db5SEtienne Carriere size_t conf_index = 0; 80470ac0db5SEtienne Carriere size_t pin_count = 0; 80570ac0db5SEtienne Carriere size_t n = 0; 80670ac0db5SEtienne Carriere 80770ac0db5SEtienne Carriere assert(count); 80870ac0db5SEtienne Carriere if (!pinctrl) 80970ac0db5SEtienne Carriere goto out; 81070ac0db5SEtienne Carriere 81170ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 81270ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 81370ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 81470ac0db5SEtienne Carriere 81570ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */ 81670ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 81770ac0db5SEtienne Carriere continue; 81870ac0db5SEtienne Carriere 81970ac0db5SEtienne Carriere if (bank || pin) { 82070ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) { 82170ac0db5SEtienne Carriere if (bank && pin_count < *count) 82270ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank; 82370ac0db5SEtienne Carriere if (pin && pin_count < *count) 82470ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin; 82570ac0db5SEtienne Carriere pin_count++; 82670ac0db5SEtienne Carriere } 82770ac0db5SEtienne Carriere } else { 82870ac0db5SEtienne Carriere pin_count += ref->count; 82970ac0db5SEtienne Carriere } 83070ac0db5SEtienne Carriere } 83170ac0db5SEtienne Carriere 83270ac0db5SEtienne Carriere out: 83370ac0db5SEtienne Carriere *count = pin_count; 83470ac0db5SEtienne Carriere } 83570ac0db5SEtienne Carriere 8367f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure) 8377f823a77SEtienne Carriere { 8387f823a77SEtienne Carriere size_t conf_index = 0; 8397f823a77SEtienne Carriere 8407f823a77SEtienne Carriere if (!pinctrl) 8417f823a77SEtienne Carriere return; 8427f823a77SEtienne Carriere 8437f823a77SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 8447f823a77SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 8457f823a77SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 8467f823a77SEtienne Carriere struct stm32_pinctrl *pc = NULL; 8477f823a77SEtienne Carriere size_t n = 0; 8487f823a77SEtienne Carriere 8497f823a77SEtienne Carriere for (n = 0; n < ref->count; n++) { 8507f823a77SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 8517f823a77SEtienne Carriere continue; 8527f823a77SEtienne Carriere 8537f823a77SEtienne Carriere pc = ref->pinctrl + n; 8547f823a77SEtienne Carriere stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure); 8557f823a77SEtienne Carriere } 8567f823a77SEtienne Carriere } 8577f823a77SEtienne Carriere } 8587f823a77SEtienne Carriere 859b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */ 860b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs, 861b38386fbSEtienne Carriere void *data __unused, 862b38386fbSEtienne Carriere struct pinconf **out_pinconf) 863b38386fbSEtienne Carriere { 864b38386fbSEtienne Carriere struct conf { 865b38386fbSEtienne Carriere struct pinconf pinconf; 866b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref; 867b38386fbSEtienne Carriere } *loc_conf = NULL; 868b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL; 869b38386fbSEtienne Carriere struct pinconf *pinconf = NULL; 870b38386fbSEtienne Carriere const void *fdt = NULL; 871b38386fbSEtienne Carriere size_t pin_count = 0; 872b38386fbSEtienne Carriere int pinctrl_node = 0; 873b38386fbSEtienne Carriere int pinmux_node = 0; 874b38386fbSEtienne Carriere int count = 0; 875b38386fbSEtienne Carriere 876b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node; 877b38386fbSEtienne Carriere fdt = pargs->fdt; 878b38386fbSEtienne Carriere assert(fdt && pinctrl_node); 879b38386fbSEtienne Carriere 880b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 881b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count)) 882b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t); 883b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND) 884b38386fbSEtienne Carriere panic(); 885b38386fbSEtienne Carriere } 886b38386fbSEtienne Carriere 887b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count); 888b38386fbSEtienne Carriere if (!loc_conf) 889b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 890b38386fbSEtienne Carriere 891b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf; 892b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops; 893b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref; 894b38386fbSEtienne Carriere 895b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count; 896b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl; 897b38386fbSEtienne Carriere 898b38386fbSEtienne Carriere count = 0; 899b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 900b38386fbSEtienne Carriere int found = 0; 901b38386fbSEtienne Carriere 902b38386fbSEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count, 903b38386fbSEtienne Carriere pin_count - count); 904b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) { 905b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */ 906b38386fbSEtienne Carriere panic(); 907b38386fbSEtienne Carriere } 908b38386fbSEtienne Carriere 909b38386fbSEtienne Carriere count += found; 910b38386fbSEtienne Carriere } 911b38386fbSEtienne Carriere 912b38386fbSEtienne Carriere *out_pinconf = pinconf; 913b38386fbSEtienne Carriere 914b38386fbSEtienne Carriere return TEE_SUCCESS; 915b38386fbSEtienne Carriere } 916b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 917b38386fbSEtienne Carriere 9180e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 9190e0435e2SEtienne Carriere const void *compat_data) 9200e0435e2SEtienne Carriere { 921b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 922b38386fbSEtienne Carriere 9230e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 924b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data); 925b38386fbSEtienne Carriere if (res) 926b38386fbSEtienne Carriere return res; 927b38386fbSEtienne Carriere 928b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 929b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get, 930b38386fbSEtienne Carriere (void *)compat_data); 931b38386fbSEtienne Carriere if (res) 932b38386fbSEtienne Carriere return res; 933b38386fbSEtienne Carriere #endif 934b38386fbSEtienne Carriere 935b38386fbSEtienne Carriere return TEE_SUCCESS; 9360e0435e2SEtienne Carriere } 9370e0435e2SEtienne Carriere 9380e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 9390e0435e2SEtienne Carriere { .compatible = "st,stm32mp135-pinctrl" }, 9400e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-pinctrl" }, 9410e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-z-pinctrl" }, 9420e0435e2SEtienne Carriere { } 9430e0435e2SEtienne Carriere }; 9440e0435e2SEtienne Carriere 9450e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 9460e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 9470e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 9480e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 9490e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 9500e0435e2SEtienne Carriere }; 951