14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 24b5e93edSEtienne Carriere /* 3bd03c8c3SGatien Chevallier * Copyright (c) 2017-2024, 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> 969715ce9SEtienne Carriere #include <compiler.h> 1097391ffbSEtienne Carriere #include <drivers/clk.h> 1197391ffbSEtienne Carriere #include <drivers/clk_dt.h> 12a650c9cbSEtienne Carriere #include <drivers/firewall.h> 13420a32c5SEtienne Carriere #include <drivers/gpio.h> 14b38386fbSEtienne Carriere #include <drivers/pinctrl.h> 154b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h> 16bd03c8c3SGatien Chevallier #include <drivers/stm32_rif.h> 17a650c9cbSEtienne Carriere #include <dt-bindings/gpio/stm32mp_gpio.h> 185f27da69SEtienne Carriere #include <dt-bindings/pinctrl/stm32-pinfunc.h> 194b5e93edSEtienne Carriere #include <io.h> 204b5e93edSEtienne Carriere #include <kernel/dt.h> 2165401337SJens Wiklander #include <kernel/boot.h> 224b5e93edSEtienne Carriere #include <kernel/panic.h> 23bfc43b68SGatien Chevallier #include <kernel/pm.h> 244b5e93edSEtienne Carriere #include <kernel/spinlock.h> 25a2fc83d1SJerome Forissier #include <libfdt.h> 264b5e93edSEtienne Carriere #include <mm/core_memprot.h> 274b5e93edSEtienne Carriere #include <stdbool.h> 2869715ce9SEtienne Carriere #include <stdint.h> 294b5e93edSEtienne Carriere #include <stm32_util.h> 309818a481SEtienne Carriere #include <sys/queue.h> 314b5e93edSEtienne Carriere #include <trace.h> 324b5e93edSEtienne Carriere #include <util.h> 334b5e93edSEtienne Carriere 344b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 354b5e93edSEtienne Carriere 365eed568cSGatien Chevallier #define GPIO_MODER_OFFSET U(0x00) 375eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET U(0x04) 385eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET U(0x08) 395eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET U(0x0c) 405eed568cSGatien Chevallier #define GPIO_IDR_OFFSET U(0x10) 415eed568cSGatien Chevallier #define GPIO_ODR_OFFSET U(0x14) 425eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET U(0x18) 435eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET U(0x20) 445eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET U(0x24) 455eed568cSGatien Chevallier #define GPIO_SECR_OFFSET U(0x30) 46bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET U(0x34) 47bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET U(0x38) 48bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x) (U(0x50) + U(0x8) * (x)) 49bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x) (U(0x54) + U(0x8) * (x)) 504b5e93edSEtienne Carriere 515eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT U(0x8) 524b5e93edSEtienne Carriere 53bd03c8c3SGatien Chevallier /* 54bd03c8c3SGatien Chevallier * CIDCFGR register bitfields 55bd03c8c3SGatien Chevallier */ 56bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK GENMASK_32(23, 16) 57bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK GENMASK_32(6, 4) 58bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK (_CIDCFGR_CFEN | _CIDCFGR_SEMEN | \ 59bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SCID_MASK | \ 60bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SEMWL_MASK) 61bd03c8c3SGatien Chevallier 62bd03c8c3SGatien Chevallier /* 63bd03c8c3SGatien Chevallier * PRIVCFGR register bitfields 64bd03c8c3SGatien Chevallier */ 65bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK GENMASK_32(15, 0) 66bd03c8c3SGatien Chevallier 67bd03c8c3SGatien Chevallier /* 68bd03c8c3SGatien Chevallier * SECCFGR register bitfields 69bd03c8c3SGatien Chevallier */ 70bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK GENMASK_32(15, 0) 71bd03c8c3SGatien Chevallier 72bd03c8c3SGatien Chevallier /* 73bd03c8c3SGatien Chevallier * RCFGLOCKR register bitfields 74bd03c8c3SGatien Chevallier */ 75bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK GENMASK_32(15, 0) 76bd03c8c3SGatien Chevallier 77bd03c8c3SGatien Chevallier /* 78bd03c8c3SGatien Chevallier * SEMCR register bitfields 79bd03c8c3SGatien Chevallier */ 80bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M GENMASK_32(6, 4) 81bd03c8c3SGatien Chevallier 824b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 834b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 844b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 85729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 864b5e93edSEtienne Carriere 875eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT U(12) 884b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 895eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT U(8) 904b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 914b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 924b5e93edSEtienne Carriere 939818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 949818a481SEtienne Carriere 9569715ce9SEtienne Carriere #define GPIO_MODE_INPUT U(0x0) 9669715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT U(0x1) 9769715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE U(0x2) 9869715ce9SEtienne Carriere #define GPIO_MODE_ANALOG U(0x3) 9969715ce9SEtienne Carriere 10069715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL U(0x0) 10169715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN U(0x1) 10269715ce9SEtienne Carriere 10369715ce9SEtienne Carriere #define GPIO_OSPEED_LOW U(0x0) 10469715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM U(0x1) 10569715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH U(0x2) 10669715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH U(0x3) 10769715ce9SEtienne Carriere 10869715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL U(0x0) 10969715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP U(0x1) 11069715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN U(0x2) 11169715ce9SEtienne Carriere 11269715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW U(0x0) 11369715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH U(0x1) 11469715ce9SEtienne Carriere 115bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED U(3) 116bd03c8c3SGatien Chevallier 11769715ce9SEtienne Carriere /* 11869715ce9SEtienne Carriere * GPIO configuration description structured as single 16bit word 11969715ce9SEtienne Carriere * for efficient save/restore when GPIO pin suspends or resumes. 12069715ce9SEtienne Carriere * 12169715ce9SEtienne Carriere * @mode: One of GPIO_MODE_* 12269715ce9SEtienne Carriere * @otype: One of GPIO_OTYPE_* 12369715ce9SEtienne Carriere * @ospeed: One of GPIO_OSPEED_* 12469715ce9SEtienne Carriere * @pupd: One of GPIO_PUPD_* 12569715ce9SEtienne Carriere * @od: One of GPIO_OD_* 12669715ce9SEtienne Carriere * @af: Alternate function numerical ID between 0 and 15 1275f27da69SEtienne Carriere * @nsec: Hint on expected secure state of the pin: 0 if secure, 1 otherwise 12869715ce9SEtienne Carriere */ 12969715ce9SEtienne Carriere struct gpio_cfg { 13069715ce9SEtienne Carriere uint16_t mode: 2; 13169715ce9SEtienne Carriere uint16_t otype: 1; 13269715ce9SEtienne Carriere uint16_t ospeed: 2; 13369715ce9SEtienne Carriere uint16_t pupd: 2; 13469715ce9SEtienne Carriere uint16_t od: 1; 13569715ce9SEtienne Carriere uint16_t af: 4; 1365f27da69SEtienne Carriere uint16_t nsec: 1; 13769715ce9SEtienne Carriere }; 13869715ce9SEtienne Carriere 13969715ce9SEtienne Carriere /* 14069715ce9SEtienne Carriere * Description of a pin and its muxing 14169715ce9SEtienne Carriere * 14269715ce9SEtienne Carriere * @bank: GPIO bank identifier as assigned by the platform 14369715ce9SEtienne Carriere * @pin: Pin number in the GPIO bank 14469715ce9SEtienne Carriere * @cfg: Pin configuration 14569715ce9SEtienne Carriere */ 14669715ce9SEtienne Carriere struct stm32_pinctrl { 14769715ce9SEtienne Carriere uint8_t bank; 14869715ce9SEtienne Carriere uint8_t pin; 14969715ce9SEtienne Carriere struct gpio_cfg cfg; 15069715ce9SEtienne Carriere }; 15169715ce9SEtienne Carriere 152b38386fbSEtienne Carriere /* 153b38386fbSEtienne Carriere * struct stm32_pinctrl_array - Array of pins in a pin control state 154b38386fbSEtienne Carriere * @count: Number of cells in @pinctrl 155b38386fbSEtienne Carriere * @pinctrl: Pin control configuration 156b38386fbSEtienne Carriere */ 157b38386fbSEtienne Carriere struct stm32_pinctrl_array { 158b38386fbSEtienne Carriere size_t count; 159b38386fbSEtienne Carriere struct stm32_pinctrl pinctrl[]; 160b38386fbSEtienne Carriere }; 161b38386fbSEtienne Carriere 1629818a481SEtienne Carriere /** 1639818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 1649818a481SEtienne Carriere * 1659818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 1669818a481SEtienne Carriere * @clock: clock identifier. 167420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 1689818a481SEtienne Carriere * @ngpios: number of GPIOs. 1699818a481SEtienne Carriere * @bank_id: Id of the bank. 1709818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 171bd03c8c3SGatien Chevallier * @rif_cfg: RIF configuration data 172bd03c8c3SGatien Chevallier * @seccfgr: non-RIF bank secure configuration data 173bd03c8c3SGatien Chevallier * @sec_support: True if bank supports pin security protection, else false 174bd03c8c3SGatien Chevallier * @ready: True if configuration is applied, else false 175bd03c8c3SGatien Chevallier * @is_tdcid: True if OP-TEE runs as Trusted Domain CID 1769818a481SEtienne Carriere * @link: Link in bank list 1779818a481SEtienne Carriere */ 1789818a481SEtienne Carriere struct stm32_gpio_bank { 1799818a481SEtienne Carriere vaddr_t base; 1809818a481SEtienne Carriere struct clk *clock; 181420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 1829818a481SEtienne Carriere unsigned int ngpios; 1839818a481SEtienne Carriere unsigned int bank_id; 1849818a481SEtienne Carriere unsigned int lock; 185bd03c8c3SGatien Chevallier struct rif_conf_data *rif_cfg; 186bd03c8c3SGatien Chevallier uint32_t seccfgr; 187b4893304SGatien Chevallier bool sec_support; 188bd03c8c3SGatien Chevallier bool ready; 189bd03c8c3SGatien Chevallier bool is_tdcid; 1909818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 1919818a481SEtienne Carriere }; 1929818a481SEtienne Carriere 193bfc43b68SGatien Chevallier /* 194bfc43b68SGatien Chevallier * struct stm32_gpio_pm_state - Consumed GPIO for PM purpose 195bfc43b68SGatien Chevallier * @gpio_pinctrl: Reference and configuration state for a consumed GPIO 196bfc43b68SGatien Chevallier * @level: GPIO level 197bfc43b68SGatien Chevallier * @link: Link in consumed GPIO list 198bfc43b68SGatien Chevallier */ 199bfc43b68SGatien Chevallier struct stm32_gpio_pm_state { 200bfc43b68SGatien Chevallier struct stm32_pinctrl gpio_pinctrl; 201bfc43b68SGatien Chevallier uint8_t level; 202bfc43b68SGatien Chevallier SLIST_ENTRY(stm32_gpio_pm_state) link; 203bfc43b68SGatien Chevallier }; 204bfc43b68SGatien Chevallier 205b4893304SGatien Chevallier /** 206e569f6adSEtienne Carriere * Compatibility information of supported banks 207b4893304SGatien Chevallier * 208b4893304SGatien Chevallier * @gpioz: True if bank is a GPIOZ bank 209b4893304SGatien Chevallier * @secure_control: Identify GPIO security bank capability. 210bd03c8c3SGatien Chevallier * @secure_extended: Identify RIF presence. 211e569f6adSEtienne Carriere */ 212e569f6adSEtienne Carriere struct bank_compat { 213e569f6adSEtienne Carriere bool gpioz; 214b4893304SGatien Chevallier bool secure_control; 215bd03c8c3SGatien Chevallier bool secure_extended; 216e569f6adSEtienne Carriere }; 217e569f6adSEtienne Carriere 2184b5e93edSEtienne Carriere static unsigned int gpio_lock; 2194b5e93edSEtienne Carriere 2209818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 2219818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 2229818a481SEtienne Carriere 223bfc43b68SGatien Chevallier static SLIST_HEAD(, stm32_gpio_pm_state) consumed_gpios_head; 224bfc43b68SGatien Chevallier 225420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 226420a32c5SEtienne Carriere 227420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 228420a32c5SEtienne Carriere { 229420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 230420a32c5SEtienne Carriere } 231420a32c5SEtienne Carriere 232*61bf256aSGatien Chevallier unsigned int stm32_gpio_chip_bank_id(struct gpio_chip *chip) 233*61bf256aSGatien Chevallier { 234*61bf256aSGatien Chevallier struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 235*61bf256aSGatien Chevallier 236*61bf256aSGatien Chevallier return bank->bank_id; 237*61bf256aSGatien Chevallier } 238*61bf256aSGatien Chevallier 239420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 240420a32c5SEtienne Carriere unsigned int gpio_pin) 241420a32c5SEtienne Carriere { 242420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 243420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 244420a32c5SEtienne Carriere unsigned int reg_offset = 0; 245420a32c5SEtienne Carriere unsigned int mode = 0; 246420a32c5SEtienne Carriere 247420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2482fd102ebSEtienne Carriere 2492fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2502fd102ebSEtienne Carriere panic(); 251420a32c5SEtienne Carriere 252420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 253420a32c5SEtienne Carriere GPIO_MODE_MASK; 254420a32c5SEtienne Carriere 255420a32c5SEtienne Carriere switch (mode) { 256420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 257420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 258420a32c5SEtienne Carriere break; 259420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 260420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 261420a32c5SEtienne Carriere break; 262420a32c5SEtienne Carriere default: 263420a32c5SEtienne Carriere panic(); 264420a32c5SEtienne Carriere } 265420a32c5SEtienne Carriere 266420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 267420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 268420a32c5SEtienne Carriere else 269420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 270420a32c5SEtienne Carriere 271420a32c5SEtienne Carriere clk_disable(bank->clock); 272420a32c5SEtienne Carriere 273420a32c5SEtienne Carriere return level; 274420a32c5SEtienne Carriere } 275420a32c5SEtienne Carriere 276420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 277420a32c5SEtienne Carriere enum gpio_level level) 278420a32c5SEtienne Carriere { 279420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 280420a32c5SEtienne Carriere 281420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2822fd102ebSEtienne Carriere 2832fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2842fd102ebSEtienne Carriere panic(); 285420a32c5SEtienne Carriere 286420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 287420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 288420a32c5SEtienne Carriere 289420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 290420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 291420a32c5SEtienne Carriere else 292420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 293420a32c5SEtienne Carriere 294420a32c5SEtienne Carriere clk_disable(bank->clock); 295420a32c5SEtienne Carriere } 296420a32c5SEtienne Carriere 297420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 298420a32c5SEtienne Carriere unsigned int gpio_pin) 299420a32c5SEtienne Carriere { 300420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 301420a32c5SEtienne Carriere uint32_t mode = 0; 302420a32c5SEtienne Carriere 303420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 3042fd102ebSEtienne Carriere 3052fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 3062fd102ebSEtienne Carriere panic(); 307420a32c5SEtienne Carriere 308420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 309420a32c5SEtienne Carriere GPIO_MODE_MASK; 310420a32c5SEtienne Carriere 311420a32c5SEtienne Carriere clk_disable(bank->clock); 312420a32c5SEtienne Carriere 313420a32c5SEtienne Carriere switch (mode) { 314420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 315420a32c5SEtienne Carriere return GPIO_DIR_IN; 316420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 317420a32c5SEtienne Carriere return GPIO_DIR_OUT; 318420a32c5SEtienne Carriere default: 319420a32c5SEtienne Carriere panic(); 320420a32c5SEtienne Carriere } 321420a32c5SEtienne Carriere } 322420a32c5SEtienne Carriere 323420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 324420a32c5SEtienne Carriere unsigned int gpio_pin, 325420a32c5SEtienne Carriere enum gpio_dir direction) 326420a32c5SEtienne Carriere { 327420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 328420a32c5SEtienne Carriere uint32_t exceptions = 0; 329420a32c5SEtienne Carriere uint32_t mode = 0; 330420a32c5SEtienne Carriere 331420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 332420a32c5SEtienne Carriere 333420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 334420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 335420a32c5SEtienne Carriere else 336420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 337420a32c5SEtienne Carriere 3382fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 3392fd102ebSEtienne Carriere panic(); 340420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 341420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 342420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 343420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 344420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 345420a32c5SEtienne Carriere clk_disable(bank->clock); 346420a32c5SEtienne Carriere } 347420a32c5SEtienne Carriere 348bfc43b68SGatien Chevallier /* Forward reference to the PM callback handler for consumed GPIOs */ 349bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, unsigned int pm_hint, 350bfc43b68SGatien Chevallier const struct pm_callback_handle *pm_hdl); 351bfc43b68SGatien Chevallier 352430c415aSEtienne Carriere /* Forward reference to RIF semaphore release helper function */ 353430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank, 354430c415aSEtienne Carriere unsigned int pin); 355430c415aSEtienne Carriere 356bfc43b68SGatien Chevallier static void stm32_gpio_put_gpio(struct gpio_chip *chip, struct gpio *gpio) 357420a32c5SEtienne Carriere { 358bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 359bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *tstate = NULL; 360bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *state = NULL; 361bfc43b68SGatien Chevallier uint32_t exceptions = 0; 362bfc43b68SGatien Chevallier 363420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 364bfc43b68SGatien Chevallier 365bfc43b68SGatien Chevallier exceptions = cpu_spin_lock_xsave(&gpio_lock); 366bfc43b68SGatien Chevallier 367bfc43b68SGatien Chevallier SLIST_FOREACH_SAFE(state, &consumed_gpios_head, link, tstate) { 368bfc43b68SGatien Chevallier if (state->gpio_pinctrl.bank == bank->bank_id && 369bfc43b68SGatien Chevallier state->gpio_pinctrl.pin == gpio->pin) { 370bfc43b68SGatien Chevallier SLIST_REMOVE(&consumed_gpios_head, state, 371bfc43b68SGatien Chevallier stm32_gpio_pm_state, link); 372bfc43b68SGatien Chevallier unregister_pm_driver_cb(consumed_gpios_pm, state); 373430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, gpio->pin); 374bfc43b68SGatien Chevallier free(state); 375420a32c5SEtienne Carriere free(gpio); 376bfc43b68SGatien Chevallier break; 377bfc43b68SGatien Chevallier } 378bfc43b68SGatien Chevallier } 379bfc43b68SGatien Chevallier assert(state); 380bfc43b68SGatien Chevallier 381bfc43b68SGatien Chevallier cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 382420a32c5SEtienne Carriere } 383420a32c5SEtienne Carriere 384420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 385420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 386420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 387420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 388420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 389420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 390420a32c5SEtienne Carriere }; 391420a32c5SEtienne Carriere 392420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 393420a32c5SEtienne Carriere { 394420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 395420a32c5SEtienne Carriere } 396420a32c5SEtienne Carriere 397077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 3984b5e93edSEtienne Carriere { 399077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 4004b5e93edSEtienne Carriere 401077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 402077d486eSEtienne Carriere if (bank_id == bank->bank_id) 403077d486eSEtienne Carriere return bank; 404077d486eSEtienne Carriere 405077d486eSEtienne Carriere panic(); 406077d486eSEtienne Carriere } 407077d486eSEtienne Carriere 408430c415aSEtienne Carriere #if defined(CFG_STM32_RIF) 4094675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank, unsigned int pin) 4104675225eSEtienne Carriere { 4114675225eSEtienne Carriere bool accessible = false; 4124675225eSEtienne Carriere uint32_t cidcfgr = 0; 4134675225eSEtienne Carriere 4144675225eSEtienne Carriere if (!bank->rif_cfg) 4154675225eSEtienne Carriere return true; 4164675225eSEtienne Carriere 4174675225eSEtienne Carriere if (clk_enable(bank->clock)) 4184675225eSEtienne Carriere panic(); 4194675225eSEtienne Carriere 4204675225eSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin)); 4214675225eSEtienne Carriere 4224675225eSEtienne Carriere if (!(cidcfgr & _CIDCFGR_CFEN)) { 4234675225eSEtienne Carriere /* Resource can be accessed when CID filtering is disabled */ 4244675225eSEtienne Carriere accessible = true; 4254675225eSEtienne Carriere } else if (stm32_rif_scid_ok(cidcfgr, GPIO_CIDCFGR_SCID_MASK, 4264675225eSEtienne Carriere RIF_CID1)) { 4274675225eSEtienne Carriere /* Resource can be accessed if CID1 is statically allowed */ 4284675225eSEtienne Carriere accessible = true; 4294675225eSEtienne Carriere } else if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) { 4304675225eSEtienne Carriere /* CID1 is allowed to request the semaphore */ 4314675225eSEtienne Carriere accessible = true; 4324675225eSEtienne Carriere } 4334675225eSEtienne Carriere 4344675225eSEtienne Carriere clk_disable(bank->clock); 4354675225eSEtienne Carriere 4364675225eSEtienne Carriere return accessible; 4374675225eSEtienne Carriere } 4384675225eSEtienne Carriere 439430c415aSEtienne Carriere static TEE_Result acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank, 440430c415aSEtienne Carriere unsigned int pin) 441430c415aSEtienne Carriere { 442430c415aSEtienne Carriere TEE_Result res = TEE_SUCCESS; 443430c415aSEtienne Carriere uint32_t cidcfgr = 0; 444430c415aSEtienne Carriere 445430c415aSEtienne Carriere if (!bank->rif_cfg) 446430c415aSEtienne Carriere return TEE_SUCCESS; 447430c415aSEtienne Carriere 448430c415aSEtienne Carriere res = clk_enable(bank->clock); 449430c415aSEtienne Carriere if (res) 450430c415aSEtienne Carriere return res; 451430c415aSEtienne Carriere 452430c415aSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin)); 453430c415aSEtienne Carriere 454430c415aSEtienne Carriere if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) 455430c415aSEtienne Carriere res = stm32_rif_acquire_semaphore(bank->base + GPIO_SEMCR(pin), 456430c415aSEtienne Carriere GPIO_MAX_CID_SUPPORTED); 457430c415aSEtienne Carriere 458430c415aSEtienne Carriere clk_disable(bank->clock); 459430c415aSEtienne Carriere 460430c415aSEtienne Carriere return res; 461430c415aSEtienne Carriere } 462430c415aSEtienne Carriere 463430c415aSEtienne Carriere static uint32_t semaphore_current_cid(struct stm32_gpio_bank *bank, 464430c415aSEtienne Carriere unsigned int pin) 465430c415aSEtienne Carriere { 466430c415aSEtienne Carriere return (io_read32(bank->base + GPIO_SEMCR(pin)) >> 467430c415aSEtienne Carriere _CIDCFGR_SCID_SHIFT) & 468430c415aSEtienne Carriere GENMASK_32(GPIO_MAX_CID_SUPPORTED - 1, 0); 469430c415aSEtienne Carriere } 470430c415aSEtienne Carriere 471430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank, 472430c415aSEtienne Carriere unsigned int pin) 473430c415aSEtienne Carriere { 474430c415aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 475430c415aSEtienne Carriere uint32_t cidcfgr = 0; 476430c415aSEtienne Carriere 477430c415aSEtienne Carriere if (!bank->rif_cfg) 478430c415aSEtienne Carriere return; 479430c415aSEtienne Carriere 480430c415aSEtienne Carriere res = clk_enable(bank->clock); 481430c415aSEtienne Carriere if (res) 482430c415aSEtienne Carriere panic(); 483430c415aSEtienne Carriere 484430c415aSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin)); 485430c415aSEtienne Carriere 486430c415aSEtienne Carriere if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1) && 487430c415aSEtienne Carriere semaphore_current_cid(bank, pin) == RIF_CID1) { 488430c415aSEtienne Carriere res = stm32_rif_release_semaphore(bank->base + GPIO_SEMCR(pin), 489430c415aSEtienne Carriere GPIO_MAX_CID_SUPPORTED); 490430c415aSEtienne Carriere if (res) { 491430c415aSEtienne Carriere EMSG("Failed to release GPIO %c%u semaphore", 492430c415aSEtienne Carriere bank->bank_id + 'A', pin); 493430c415aSEtienne Carriere panic(); 494430c415aSEtienne Carriere } 495430c415aSEtienne Carriere } 496430c415aSEtienne Carriere 497430c415aSEtienne Carriere clk_disable(bank->clock); 498430c415aSEtienne Carriere } 499430c415aSEtienne Carriere #else 5004675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank __unused, 5014675225eSEtienne Carriere unsigned int pin __unused) 5024675225eSEtienne Carriere { 5034675225eSEtienne Carriere return true; 5044675225eSEtienne Carriere } 5054675225eSEtienne Carriere 506430c415aSEtienne Carriere static TEE_Result 507430c415aSEtienne Carriere acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank __unused, 508430c415aSEtienne Carriere unsigned int pin __unused) 509430c415aSEtienne Carriere { 510430c415aSEtienne Carriere return TEE_SUCCESS; 511430c415aSEtienne Carriere } 512430c415aSEtienne Carriere 513430c415aSEtienne Carriere static void 514430c415aSEtienne Carriere release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank __unused, 515430c415aSEtienne Carriere unsigned int pin __unused) 516430c415aSEtienne Carriere { 517430c415aSEtienne Carriere } 518430c415aSEtienne Carriere #endif /*CFG_STM32_RIF*/ 519430c415aSEtienne Carriere 5204675225eSEtienne Carriere static bool pin_is_secure(struct stm32_gpio_bank *bank, unsigned int pin) 5214675225eSEtienne Carriere { 5224675225eSEtienne Carriere bool secure = false; 5234675225eSEtienne Carriere 5244675225eSEtienne Carriere if (bank->rif_cfg || bank->sec_support) { 5254675225eSEtienne Carriere if (clk_enable(bank->clock)) 5264675225eSEtienne Carriere panic(); 5274675225eSEtienne Carriere 5284675225eSEtienne Carriere secure = io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(pin); 5294675225eSEtienne Carriere 5304675225eSEtienne Carriere clk_disable(bank->clock); 5314675225eSEtienne Carriere } 5324675225eSEtienne Carriere 5334675225eSEtienne Carriere return secure; 5344675225eSEtienne Carriere } 5354675225eSEtienne Carriere 536077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 537bfc43b68SGatien Chevallier static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 538077d486eSEtienne Carriere { 539077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 540077d486eSEtienne Carriere 541077d486eSEtienne Carriere if (clk_enable(bank->clock)) 542077d486eSEtienne Carriere panic(); 5434b5e93edSEtienne Carriere 5444b5e93edSEtienne Carriere /* 5454b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 5464b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 5474b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 5484b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 5494b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 5504b5e93edSEtienne Carriere */ 551077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 5524b5e93edSEtienne Carriere GPIO_MODE_MASK; 5534b5e93edSEtienne Carriere 554077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 5554b5e93edSEtienne Carriere 556077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 557077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 5584b5e93edSEtienne Carriere 559077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 5604b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 5614b5e93edSEtienne Carriere 562077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 5634b5e93edSEtienne Carriere 5644b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 565077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 566077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 5674b5e93edSEtienne Carriere else 568077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 5694b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 5704b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 5714b5e93edSEtienne Carriere 572077d486eSEtienne Carriere clk_disable(bank->clock); 5734b5e93edSEtienne Carriere } 5744b5e93edSEtienne Carriere 5754b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 576077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 5774b5e93edSEtienne Carriere { 578077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 57998dfcedaSEtienne Carriere uint32_t exceptions = 0; 5804b5e93edSEtienne Carriere 581077d486eSEtienne Carriere if (clk_enable(bank->clock)) 582077d486eSEtienne Carriere panic(); 58398dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 5844b5e93edSEtienne Carriere 5854b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 586077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 587bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 588bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 5894b5e93edSEtienne Carriere 5904b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 591077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 592bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 5934b5e93edSEtienne Carriere 5944b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 595077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 596bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 597bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 5984b5e93edSEtienne Carriere 5994b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 600077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 601bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 6024b5e93edSEtienne Carriere 6034b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 6044b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 605077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 606bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 607bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 6084b5e93edSEtienne Carriere } else { 6094b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 6104b5e93edSEtienne Carriere 611077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 612bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 613bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 6144b5e93edSEtienne Carriere } 6154b5e93edSEtienne Carriere 6164b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 617077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 6184b5e93edSEtienne Carriere 619c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 62098dfcedaSEtienne Carriere clk_disable(bank->clock); 6214b5e93edSEtienne Carriere } 6224b5e93edSEtienne Carriere 6234b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 624b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node, 6255f27da69SEtienne Carriere int consumer_node __maybe_unused, 6264b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 6274b5e93edSEtienne Carriere { 6285f27da69SEtienne Carriere struct stm32_gpio_bank *bank_ref = NULL; 629b38386fbSEtienne Carriere const fdt32_t *cuint = NULL; 630b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL; 63110bcbd6cSEtienne Carriere int len = 0; 63210bcbd6cSEtienne Carriere uint32_t i = 0; 6334b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 6344b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 6354b5e93edSEtienne Carriere size_t found = 0; 6365f27da69SEtienne Carriere bool do_panic = false; 6374b5e93edSEtienne Carriere 6384b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 6394b5e93edSEtienne Carriere if (!cuint) 6404b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 6414b5e93edSEtienne Carriere 6424b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 6434b5e93edSEtienne Carriere if (slewrate) 6444b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 6454b5e93edSEtienne Carriere 6464b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 6474b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 6484b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 6494b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 6504b5e93edSEtienne Carriere 6514b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 65210bcbd6cSEtienne Carriere uint32_t pincfg = 0; 65310bcbd6cSEtienne Carriere uint32_t bank = 0; 65410bcbd6cSEtienne Carriere uint32_t pin = 0; 65510bcbd6cSEtienne Carriere uint32_t mode = 0; 6564b5e93edSEtienne Carriere uint32_t alternate = 0; 657322cf9e3SEtienne Carriere uint32_t odata = 0; 6584b5e93edSEtienne Carriere bool opendrain = false; 6595f27da69SEtienne Carriere bool pin_non_secure = true; 6604b5e93edSEtienne Carriere 6614b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 6624b5e93edSEtienne Carriere cuint++; 6634b5e93edSEtienne Carriere 6644b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 6654b5e93edSEtienne Carriere 6664b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 6674b5e93edSEtienne Carriere 6684b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 6694b5e93edSEtienne Carriere 6705f27da69SEtienne Carriere pin_non_secure = pincfg & STM32_PIN_NSEC; 6715f27da69SEtienne Carriere 6724b5e93edSEtienne Carriere switch (mode) { 6734b5e93edSEtienne Carriere case 0: 6744b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 6754b5e93edSEtienne Carriere break; 6764b5e93edSEtienne Carriere case 1: 6774b5e93edSEtienne Carriere case 2: 6784b5e93edSEtienne Carriere case 3: 6794b5e93edSEtienne Carriere case 4: 6804b5e93edSEtienne Carriere case 5: 6814b5e93edSEtienne Carriere case 6: 6824b5e93edSEtienne Carriere case 7: 6834b5e93edSEtienne Carriere case 8: 6844b5e93edSEtienne Carriere case 9: 6854b5e93edSEtienne Carriere case 10: 6864b5e93edSEtienne Carriere case 11: 6874b5e93edSEtienne Carriere case 12: 6884b5e93edSEtienne Carriere case 13: 6894b5e93edSEtienne Carriere case 14: 6904b5e93edSEtienne Carriere case 15: 6914b5e93edSEtienne Carriere case 16: 6924b5e93edSEtienne Carriere alternate = mode - 1U; 6934b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 6944b5e93edSEtienne Carriere break; 6954b5e93edSEtienne Carriere case 17: 6964b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 6974b5e93edSEtienne Carriere break; 6984b5e93edSEtienne Carriere default: 6994b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 7004b5e93edSEtienne Carriere break; 7014b5e93edSEtienne Carriere } 7024b5e93edSEtienne Carriere 7034b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 7044b5e93edSEtienne Carriere opendrain = true; 7054b5e93edSEtienne Carriere 706322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 707322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 708322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 709322cf9e3SEtienne Carriere odata = 1; 710322cf9e3SEtienne Carriere } 711322cf9e3SEtienne Carriere 712322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 713322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 714322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 715322cf9e3SEtienne Carriere odata = 0; 716322cf9e3SEtienne Carriere } 717322cf9e3SEtienne Carriere 7184b5e93edSEtienne Carriere if (found < count) { 7194b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 7204b5e93edSEtienne Carriere 7214b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 7224b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 723b38386fbSEtienne Carriere ref->cfg.mode = mode; 724b38386fbSEtienne Carriere if (opendrain) 725b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN; 726b38386fbSEtienne Carriere else 727b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL; 728b38386fbSEtienne Carriere ref->cfg.ospeed = speed; 729b38386fbSEtienne Carriere ref->cfg.pupd = pull; 730b38386fbSEtienne Carriere ref->cfg.od = odata; 731b38386fbSEtienne Carriere ref->cfg.af = alternate; 7325f27da69SEtienne Carriere ref->cfg.nsec = pin_non_secure; 7335f27da69SEtienne Carriere 7345f27da69SEtienne Carriere bank_ref = stm32_gpio_get_bank(bank); 7355f27da69SEtienne Carriere 7365f27da69SEtienne Carriere if (pin >= bank_ref->ngpios) { 7375f27da69SEtienne Carriere EMSG("node %s requests pin %c%u that does not exist", 7385f27da69SEtienne Carriere fdt_get_name(fdt, consumer_node, NULL), 7395f27da69SEtienne Carriere bank + 'A', pin); 7405f27da69SEtienne Carriere do_panic = true; 7415f27da69SEtienne Carriere } 7424b5e93edSEtienne Carriere } 7434b5e93edSEtienne Carriere 7444b5e93edSEtienne Carriere found++; 7454b5e93edSEtienne Carriere } 7464b5e93edSEtienne Carriere 7475f27da69SEtienne Carriere if (do_panic) 7485f27da69SEtienne Carriere panic(); 7495f27da69SEtienne Carriere 7504b5e93edSEtienne Carriere return (int)found; 7514b5e93edSEtienne Carriere } 7524b5e93edSEtienne Carriere 753bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, 754bfc43b68SGatien Chevallier unsigned int pm_hint __unused, 755bfc43b68SGatien Chevallier const struct pm_callback_handle *pm_hdl) 756bfc43b68SGatien Chevallier { 757bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *handle = pm_hdl->handle; 758bfc43b68SGatien Chevallier unsigned int bank_id = handle->gpio_pinctrl.bank; 759bfc43b68SGatien Chevallier unsigned int pin = handle->gpio_pinctrl.pin; 760bfc43b68SGatien Chevallier struct gpio_chip *chip = &stm32_gpio_get_bank(bank_id)->gpio_chip; 761bfc43b68SGatien Chevallier 762bfc43b68SGatien Chevallier if (op == PM_OP_RESUME) { 763bfc43b68SGatien Chevallier set_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg); 764bfc43b68SGatien Chevallier if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT) 765bfc43b68SGatien Chevallier stm32_gpio_set_level(chip, pin, handle->level); 766bfc43b68SGatien Chevallier } else { 767bfc43b68SGatien Chevallier get_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg); 768bfc43b68SGatien Chevallier if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT) 769bfc43b68SGatien Chevallier handle->level = stm32_gpio_get_level(chip, pin); 770bfc43b68SGatien Chevallier } 771bfc43b68SGatien Chevallier 772bfc43b68SGatien Chevallier return TEE_SUCCESS; 773bfc43b68SGatien Chevallier } 774bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(consumed_gpios_pm); 775bfc43b68SGatien Chevallier 776b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data, 777b357d34fSEtienne Carriere struct gpio **out_gpio) 778420a32c5SEtienne Carriere { 779b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 780430c415aSEtienne Carriere const char *consumer_name __maybe_unused = NULL; 7817761b658SEtienne Carriere struct stm32_gpio_pm_state *reg_state = NULL; 782bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *state = NULL; 783420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 784420a32c5SEtienne Carriere struct gpio *gpio = NULL; 785420a32c5SEtienne Carriere unsigned int shift_1b = 0; 786420a32c5SEtienne Carriere unsigned int shift_2b = 0; 7874675225eSEtienne Carriere bool gpio_secure = true; 788420a32c5SEtienne Carriere uint32_t exceptions = 0; 789420a32c5SEtienne Carriere uint32_t otype = 0; 790420a32c5SEtienne Carriere uint32_t pupd = 0; 791420a32c5SEtienne Carriere uint32_t mode = 0; 792420a32c5SEtienne Carriere 793430c415aSEtienne Carriere consumer_name = fdt_get_name(pargs->fdt, pargs->consumer_node, 794430c415aSEtienne Carriere NULL); 795430c415aSEtienne Carriere 796b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio); 797b357d34fSEtienne Carriere if (res) 798b357d34fSEtienne Carriere return res; 799420a32c5SEtienne Carriere 800420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 801420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 802420a32c5SEtienne Carriere free(gpio); 803b357d34fSEtienne Carriere return TEE_ERROR_GENERIC; 804420a32c5SEtienne Carriere } 805420a32c5SEtienne Carriere 8064675225eSEtienne Carriere if (gpio->dt_flags & GPIO_STM32_NSEC) 8074675225eSEtienne Carriere gpio_secure = false; 8084675225eSEtienne Carriere 809bfc43b68SGatien Chevallier state = calloc(1, sizeof(*state)); 810bfc43b68SGatien Chevallier if (!state) { 811bfc43b68SGatien Chevallier free(gpio); 812bfc43b68SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY; 813bfc43b68SGatien Chevallier } 814bfc43b68SGatien Chevallier 8157761b658SEtienne Carriere SLIST_FOREACH(reg_state, &consumed_gpios_head, link) { 8167761b658SEtienne Carriere if (reg_state->gpio_pinctrl.bank == bank->bank_id && 8177761b658SEtienne Carriere reg_state->gpio_pinctrl.pin == gpio->pin) { 8187761b658SEtienne Carriere EMSG("node %s: GPIO %c%u is used by another device", 8194675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin); 8207761b658SEtienne Carriere free(state); 8217761b658SEtienne Carriere free(gpio); 8227761b658SEtienne Carriere return TEE_ERROR_GENERIC; 8237761b658SEtienne Carriere } 8247761b658SEtienne Carriere } 8257761b658SEtienne Carriere 8264675225eSEtienne Carriere if (!pin_is_accessible(bank, gpio->pin)) { 8274675225eSEtienne Carriere EMSG("node %s requests pin on GPIO %c%u which access is denied", 8284675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin); 8294675225eSEtienne Carriere panic(); 8304675225eSEtienne Carriere } 8314675225eSEtienne Carriere 832430c415aSEtienne Carriere res = acquire_rif_semaphore_if_needed(bank, gpio->pin); 833430c415aSEtienne Carriere if (res) { 834430c415aSEtienne Carriere EMSG("Failed to acquire GPIO %c%u semaphore for node %s", 835430c415aSEtienne Carriere bank->bank_id + 'A', gpio->pin, consumer_name); 836430c415aSEtienne Carriere return res; 837430c415aSEtienne Carriere } 838430c415aSEtienne Carriere 8394675225eSEtienne Carriere if (gpio_secure && !(bank->rif_cfg || bank->sec_support)) { 8404675225eSEtienne Carriere EMSG("node %s requests secure GPIO %c%u that cannot be secured", 8414675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin); 8424675225eSEtienne Carriere panic(); 8434675225eSEtienne Carriere } 8444675225eSEtienne Carriere 8454675225eSEtienne Carriere if (gpio_secure != pin_is_secure(bank, gpio->pin)) { 8464675225eSEtienne Carriere IMSG("WARNING: node %s requests %s GPIO %c%u but pin is %s. Check st,protreg in GPIO bank node %s", 8474675225eSEtienne Carriere consumer_name, gpio_secure ? "secure" : "non-secure", 8484675225eSEtienne Carriere bank->bank_id + 'A', gpio->pin, 8494675225eSEtienne Carriere pin_is_secure(bank, gpio->pin) ? "secure" : "non-secure", 8504675225eSEtienne Carriere fdt_get_name(pargs->fdt, pargs->phandle_node, NULL)); 8514675225eSEtienne Carriere if (!IS_ENABLED(CFG_INSECURE)) 8524675225eSEtienne Carriere panic(); 8534675225eSEtienne Carriere } 8544675225eSEtienne Carriere 855bfc43b68SGatien Chevallier state->gpio_pinctrl.pin = gpio->pin; 856bfc43b68SGatien Chevallier state->gpio_pinctrl.bank = bank->bank_id; 857bfc43b68SGatien Chevallier SLIST_INSERT_HEAD(&consumed_gpios_head, state, link); 858bfc43b68SGatien Chevallier 859bfc43b68SGatien Chevallier register_pm_driver_cb(consumed_gpios_pm, state, "stm32-gpio-state"); 860bfc43b68SGatien Chevallier 861420a32c5SEtienne Carriere shift_1b = gpio->pin; 862420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 863420a32c5SEtienne Carriere 864420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 865420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 866420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 867420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 868420a32c5SEtienne Carriere else 869420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 870420a32c5SEtienne Carriere 871420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 872420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 873420a32c5SEtienne Carriere else 874420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 875420a32c5SEtienne Carriere 876420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 877420a32c5SEtienne Carriere panic(); 878420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 879420a32c5SEtienne Carriere 880420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 881420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 882420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 883420a32c5SEtienne Carriere 884420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 885420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 886420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 887420a32c5SEtienne Carriere 888420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 889420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 890420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 891420a32c5SEtienne Carriere 892420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 893420a32c5SEtienne Carriere clk_disable(bank->clock); 894420a32c5SEtienne Carriere 895420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 896420a32c5SEtienne Carriere 897b357d34fSEtienne Carriere *out_gpio = gpio; 898420a32c5SEtienne Carriere 899b357d34fSEtienne Carriere return TEE_SUCCESS; 900420a32c5SEtienne Carriere } 901420a32c5SEtienne Carriere 9029818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 9039818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 9049818a481SEtienne Carriere { 9059818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 9069818a481SEtienne Carriere const fdt32_t *cuint = NULL; 9079818a481SEtienne Carriere int len = 0; 9089818a481SEtienne Carriere 9099818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 9109818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 9119818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 9129818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 9139818a481SEtienne Carriere 9149818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 9159818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 9169818a481SEtienne Carriere panic("Wrong st,bank-name property"); 9179818a481SEtienne Carriere 9189818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 9199818a481SEtienne Carriere } 9209818a481SEtienne Carriere 9219818a481SEtienne Carriere /* 9229818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 9239818a481SEtienne Carriere * registered in the GPIO bank link. 9249818a481SEtienne Carriere */ 9259818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 9269818a481SEtienne Carriere { 9279818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 9289818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 9299818a481SEtienne Carriere 9309818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 9319818a481SEtienne Carriere if (bank->bank_id == bank_id) 9329818a481SEtienne Carriere return true; 9339818a481SEtienne Carriere 9349818a481SEtienne Carriere return false; 9359818a481SEtienne Carriere } 9369818a481SEtienne Carriere 9379def1fb7SGatien Chevallier #ifdef CFG_STM32_RIF 938a72f07daSEtienne Carriere static TEE_Result handle_available_semaphores(struct stm32_gpio_bank *bank, 939a72f07daSEtienne Carriere uint32_t gpios_mask) 940bd03c8c3SGatien Chevallier { 941bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 942bd03c8c3SGatien Chevallier uint32_t cidcfgr = 0; 943bd03c8c3SGatien Chevallier unsigned int i = 0; 944bd03c8c3SGatien Chevallier 9459def1fb7SGatien Chevallier for (i = 0 ; i < bank->ngpios; i++) { 946a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask)) 9479def1fb7SGatien Chevallier continue; 9489def1fb7SGatien Chevallier 9499def1fb7SGatien Chevallier cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i)); 9509def1fb7SGatien Chevallier 9519def1fb7SGatien Chevallier if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) 9529def1fb7SGatien Chevallier continue; 9539def1fb7SGatien Chevallier 9549def1fb7SGatien Chevallier if (!(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) { 9559def1fb7SGatien Chevallier res = stm32_rif_release_semaphore(bank->base + 9569def1fb7SGatien Chevallier GPIO_SEMCR(i), 9579def1fb7SGatien Chevallier MAX_CID_SUPPORTED); 9589def1fb7SGatien Chevallier if (res) { 9599def1fb7SGatien Chevallier EMSG("Cannot release semaphore for resource %u", 9609def1fb7SGatien Chevallier i); 9619def1fb7SGatien Chevallier return res; 9629def1fb7SGatien Chevallier } 9639def1fb7SGatien Chevallier } else { 9649def1fb7SGatien Chevallier res = stm32_rif_acquire_semaphore(bank->base + 9659def1fb7SGatien Chevallier GPIO_SEMCR(i), 9669def1fb7SGatien Chevallier MAX_CID_SUPPORTED); 9679def1fb7SGatien Chevallier if (res) { 9689def1fb7SGatien Chevallier EMSG("Cannot acquire semaphore for resource %u", 9699def1fb7SGatien Chevallier i); 9709def1fb7SGatien Chevallier return res; 9719def1fb7SGatien Chevallier } 9729def1fb7SGatien Chevallier } 9739def1fb7SGatien Chevallier } 9749def1fb7SGatien Chevallier 9759def1fb7SGatien Chevallier return TEE_SUCCESS; 9769def1fb7SGatien Chevallier } 9779def1fb7SGatien Chevallier 978a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank, 979a72f07daSEtienne Carriere uint32_t gpios_mask) 9809def1fb7SGatien Chevallier { 9819def1fb7SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 9829def1fb7SGatien Chevallier unsigned int i = 0; 9839def1fb7SGatien Chevallier 984bd03c8c3SGatien Chevallier if (!bank->rif_cfg) 985bd03c8c3SGatien Chevallier return TEE_SUCCESS; 986bd03c8c3SGatien Chevallier 987bd03c8c3SGatien Chevallier if (clk_enable(bank->clock)) 988bd03c8c3SGatien Chevallier panic(); 989bd03c8c3SGatien Chevallier 9909def1fb7SGatien Chevallier if (bank->is_tdcid) { 991bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) { 992a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask)) 993bd03c8c3SGatien Chevallier continue; 994bd03c8c3SGatien Chevallier 995bd03c8c3SGatien Chevallier /* 9969def1fb7SGatien Chevallier * When TDCID, OP-TEE should be the one to set the CID 9979def1fb7SGatien Chevallier * filtering configuration. Clearing previous 9989def1fb7SGatien Chevallier * configuration prevents undesired events during the 9999def1fb7SGatien Chevallier * only legitimate configuration. 1000bd03c8c3SGatien Chevallier */ 1001bd03c8c3SGatien Chevallier io_clrbits32(bank->base + GPIO_CIDCFGR(i), 1002bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK); 1003bd03c8c3SGatien Chevallier } 10049def1fb7SGatien Chevallier } else { 1005a72f07daSEtienne Carriere res = handle_available_semaphores(bank, gpios_mask); 10069def1fb7SGatien Chevallier if (res) 10079def1fb7SGatien Chevallier panic(); 1008bd03c8c3SGatien Chevallier } 1009bd03c8c3SGatien Chevallier 1010bd03c8c3SGatien Chevallier /* Security and privilege RIF configuration */ 1011a72f07daSEtienne Carriere io_mask32(bank->base + GPIO_PRIVCFGR_OFFSET, 1012a72f07daSEtienne Carriere bank->rif_cfg->priv_conf[0], gpios_mask); 1013a72f07daSEtienne Carriere io_mask32(bank->base + GPIO_SECR_OFFSET, 1014a72f07daSEtienne Carriere bank->rif_cfg->sec_conf[0], gpios_mask); 1015bd03c8c3SGatien Chevallier 1016bd03c8c3SGatien Chevallier if (!bank->is_tdcid) { 1017bd03c8c3SGatien Chevallier res = TEE_SUCCESS; 1018bd03c8c3SGatien Chevallier goto out; 1019bd03c8c3SGatien Chevallier } 1020bd03c8c3SGatien Chevallier 1021bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) { 1022a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask)) 1023bd03c8c3SGatien Chevallier continue; 1024bd03c8c3SGatien Chevallier 1025bd03c8c3SGatien Chevallier io_clrsetbits32(bank->base + GPIO_CIDCFGR(i), 1026bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK, 1027bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs[i]); 1028bd03c8c3SGatien Chevallier } 1029bd03c8c3SGatien Chevallier 1030bd03c8c3SGatien Chevallier /* 1031bd03c8c3SGatien Chevallier * Lock RIF configuration if configured. This cannot be undone until 1032bd03c8c3SGatien Chevallier * next reset. 1033bd03c8c3SGatien Chevallier */ 1034bd03c8c3SGatien Chevallier io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET, 1035bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf[0]); 1036bd03c8c3SGatien Chevallier 1037a72f07daSEtienne Carriere res = handle_available_semaphores(bank, gpios_mask); 10389def1fb7SGatien Chevallier if (res) 10399def1fb7SGatien Chevallier panic(); 10409def1fb7SGatien Chevallier 10419def1fb7SGatien Chevallier out: 1042bd03c8c3SGatien Chevallier if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) { 1043bd03c8c3SGatien Chevallier /* Check that RIF config are applied, panic otherwise */ 1044bd03c8c3SGatien Chevallier if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) & 1045a72f07daSEtienne Carriere gpios_mask) != 1046a72f07daSEtienne Carriere (bank->rif_cfg->priv_conf[0] & gpios_mask)) { 1047bd03c8c3SGatien Chevallier EMSG("GPIO bank%c priv conf is incorrect", 1048bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 1049bd03c8c3SGatien Chevallier panic(); 1050bd03c8c3SGatien Chevallier } 1051bd03c8c3SGatien Chevallier 1052a72f07daSEtienne Carriere if ((io_read32(bank->base + GPIO_SECR_OFFSET) & gpios_mask) != 1053a72f07daSEtienne Carriere (bank->rif_cfg->sec_conf[0] & gpios_mask)) { 1054bd03c8c3SGatien Chevallier EMSG("GPIO bank %c sec conf is incorrect", 1055bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 1056bd03c8c3SGatien Chevallier panic(); 1057bd03c8c3SGatien Chevallier } 1058bd03c8c3SGatien Chevallier } 1059bd03c8c3SGatien Chevallier 1060bd03c8c3SGatien Chevallier clk_disable(bank->clock); 1061bd03c8c3SGatien Chevallier 1062bd03c8c3SGatien Chevallier return res; 1063bd03c8c3SGatien Chevallier } 10649def1fb7SGatien Chevallier #else /* CFG_STM32_RIF */ 1065a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank __unused, 1066a72f07daSEtienne Carriere uint32_t gpios_mask __unused) 10679def1fb7SGatien Chevallier { 10689def1fb7SGatien Chevallier return TEE_SUCCESS; 10699def1fb7SGatien Chevallier } 10709def1fb7SGatien Chevallier #endif /* CFG_STM32_RIF */ 1071bd03c8c3SGatien Chevallier 1072a650c9cbSEtienne Carriere /* Forward reference to stm32_gpio_set_conf_sec() defined below */ 1073a650c9cbSEtienne Carriere static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank); 1074a650c9cbSEtienne Carriere 1075a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_fw_configure(struct firewall_query *firewall) 1076a650c9cbSEtienne Carriere { 1077a650c9cbSEtienne Carriere struct stm32_gpio_bank *bank = firewall->ctrl->priv; 1078a650c9cbSEtienne Carriere uint32_t firewall_arg = 0; 1079a650c9cbSEtienne Carriere uint32_t gpios_mask = 0; 1080a650c9cbSEtienne Carriere bool secure = true; 1081a650c9cbSEtienne Carriere 1082a650c9cbSEtienne Carriere assert(bank->sec_support); 1083a650c9cbSEtienne Carriere 1084a650c9cbSEtienne Carriere if (firewall->arg_count != 1) 1085a650c9cbSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 1086a650c9cbSEtienne Carriere 1087a650c9cbSEtienne Carriere firewall_arg = firewall->args[0]; 1088a650c9cbSEtienne Carriere 1089a650c9cbSEtienne Carriere if (bank->rif_cfg) { 1090a650c9cbSEtienne Carriere gpios_mask = BIT(RIF_CHANNEL_ID(firewall_arg)); 1091a650c9cbSEtienne Carriere 1092a650c9cbSEtienne Carriere /* We're about to change a specific GPIO config */ 1093a650c9cbSEtienne Carriere bank->rif_cfg->access_mask[0] |= gpios_mask; 1094a650c9cbSEtienne Carriere 1095a650c9cbSEtienne Carriere /* 1096a650c9cbSEtienne Carriere * Update bank RIF config with firewall configuration data 1097a650c9cbSEtienne Carriere * and apply it. 1098a650c9cbSEtienne Carriere */ 1099a650c9cbSEtienne Carriere stm32_rif_parse_cfg(firewall_arg, bank->rif_cfg, 1100a650c9cbSEtienne Carriere bank->ngpios); 1101a650c9cbSEtienne Carriere return apply_rif_config(bank, gpios_mask); 1102a650c9cbSEtienne Carriere } 1103a650c9cbSEtienne Carriere 1104a650c9cbSEtienne Carriere /* 1105a650c9cbSEtienne Carriere * Non RIF GPIO banks use a single cell as a bit mask (bits 0 to 15) 1106a650c9cbSEtienne Carriere * to define the a group of GPIO pins (one or several) to configure 1107a650c9cbSEtienne Carriere * for that bank, and GPIO_STM32_NSEC bit flag to set if these pins 1108a650c9cbSEtienne Carriere * are non-secure (flag set) or non-secure (flag cleared). 1109a650c9cbSEtienne Carriere */ 1110a650c9cbSEtienne Carriere gpios_mask = firewall_arg & GENMASK_32(15, 0); 1111a650c9cbSEtienne Carriere 1112a650c9cbSEtienne Carriere secure = !(firewall_arg & GPIO_STM32_NSEC); 1113a650c9cbSEtienne Carriere 1114a650c9cbSEtienne Carriere if (gpios_mask & ~GENMASK_32(bank->ngpios, 0)) { 1115a650c9cbSEtienne Carriere EMSG("Invalid bitmask %#"PRIx32" for GPIO bank %c", 1116a650c9cbSEtienne Carriere gpios_mask, 'A' + bank->bank_id); 1117a650c9cbSEtienne Carriere return TEE_ERROR_GENERIC; 1118a650c9cbSEtienne Carriere } 1119a650c9cbSEtienne Carriere 1120a650c9cbSEtienne Carriere /* Update bank secure register configuration data and apply it */ 1121a650c9cbSEtienne Carriere if (secure) 1122a650c9cbSEtienne Carriere bank->seccfgr |= gpios_mask; 1123a650c9cbSEtienne Carriere else 1124a650c9cbSEtienne Carriere bank->seccfgr &= ~gpios_mask; 1125a650c9cbSEtienne Carriere 1126a650c9cbSEtienne Carriere stm32_gpio_set_conf_sec(bank); 1127a650c9cbSEtienne Carriere 1128a650c9cbSEtienne Carriere return TEE_SUCCESS; 1129a650c9cbSEtienne Carriere } 1130a650c9cbSEtienne Carriere 1131a650c9cbSEtienne Carriere static const struct firewall_controller_ops stm32_gpio_firewall_ops = { 1132a650c9cbSEtienne Carriere .set_conf = stm32_gpio_fw_configure, 1133a650c9cbSEtienne Carriere }; 1134a650c9cbSEtienne Carriere 1135bfc43b68SGatien Chevallier static void stm32_gpio_save_rif_config(struct stm32_gpio_bank *bank) 1136bfc43b68SGatien Chevallier { 1137bfc43b68SGatien Chevallier size_t i = 0; 1138bfc43b68SGatien Chevallier 1139bfc43b68SGatien Chevallier for (i = 0; i < bank->ngpios; i++) 1140bfc43b68SGatien Chevallier bank->rif_cfg->cid_confs[i] = io_read32(bank->base + 1141bfc43b68SGatien Chevallier GPIO_CIDCFGR(i)); 1142bfc43b68SGatien Chevallier 1143bfc43b68SGatien Chevallier bank->rif_cfg->priv_conf[0] = io_read32(bank->base + 1144bfc43b68SGatien Chevallier GPIO_PRIVCFGR_OFFSET); 1145bfc43b68SGatien Chevallier bank->rif_cfg->sec_conf[0] = io_read32(bank->base + 1146bfc43b68SGatien Chevallier GPIO_SECR_OFFSET); 1147bfc43b68SGatien Chevallier bank->rif_cfg->lock_conf[0] = io_read32(bank->base + 1148bfc43b68SGatien Chevallier GPIO_RCFGLOCKR_OFFSET); 1149bfc43b68SGatien Chevallier } 1150bfc43b68SGatien Chevallier 1151bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank, 1152bd03c8c3SGatien Chevallier const void *fdt, int node) 1153bd03c8c3SGatien Chevallier { 1154bd03c8c3SGatien Chevallier unsigned int i = 0; 1155bd03c8c3SGatien Chevallier unsigned int nb_rif_conf = 0; 1156bd03c8c3SGatien Chevallier int lenp = 0; 1157bd03c8c3SGatien Chevallier const fdt32_t *cuint = NULL; 1158bd03c8c3SGatien Chevallier 1159bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); 1160bd03c8c3SGatien Chevallier if (!cuint) { 1161bd03c8c3SGatien Chevallier DMSG("No RIF configuration available"); 1162bd03c8c3SGatien Chevallier return; 1163bd03c8c3SGatien Chevallier } 1164bd03c8c3SGatien Chevallier 1165bd03c8c3SGatien Chevallier bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg)); 1166bd03c8c3SGatien Chevallier if (!bank->rif_cfg) 1167bd03c8c3SGatien Chevallier panic(); 1168bd03c8c3SGatien Chevallier 1169bd03c8c3SGatien Chevallier bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t)); 1170bd03c8c3SGatien Chevallier if (!bank->rif_cfg->sec_conf) 1171bd03c8c3SGatien Chevallier panic(); 1172bd03c8c3SGatien Chevallier 1173bd03c8c3SGatien Chevallier nb_rif_conf = (unsigned int)(lenp / sizeof(uint32_t)); 1174bd03c8c3SGatien Chevallier assert(nb_rif_conf <= bank->ngpios); 1175bd03c8c3SGatien Chevallier 1176bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t)); 1177bd03c8c3SGatien Chevallier bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t)); 1178bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t)); 1179bd03c8c3SGatien Chevallier bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t)); 1180bd03c8c3SGatien Chevallier if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask || 1181bd03c8c3SGatien Chevallier !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf) 1182bd03c8c3SGatien Chevallier panic("Missing memory capacity for GPIOS RIF configuration"); 1183bd03c8c3SGatien Chevallier 1184bd03c8c3SGatien Chevallier for (i = 0; i < nb_rif_conf; i++) 1185bd03c8c3SGatien Chevallier stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg, 1186646ad62bSGatien Chevallier bank->ngpios); 1187bd03c8c3SGatien Chevallier } 1188bd03c8c3SGatien Chevallier 11899818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 11909818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 1191e569f6adSEtienne Carriere const void *compat_data, 11929818a481SEtienne Carriere int range_offset, 11939818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 11949818a481SEtienne Carriere { 1195e569f6adSEtienne Carriere const struct bank_compat *compat = compat_data; 11969818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 11979818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 11989818a481SEtienne Carriere const fdt32_t *cuint = NULL; 11999818a481SEtienne Carriere struct io_pa_va pa_va = { }; 12009818a481SEtienne Carriere struct clk *clk = NULL; 12019818a481SEtienne Carriere size_t blen = 0; 12029818a481SEtienne Carriere paddr_t pa = 0; 12039818a481SEtienne Carriere int len = 0; 12049818a481SEtienne Carriere int i = 0; 12059818a481SEtienne Carriere 12069818a481SEtienne Carriere assert(out_bank); 12079818a481SEtienne Carriere 12089818a481SEtienne Carriere /* Probe deferrable devices first */ 12099818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 12109818a481SEtienne Carriere if (res) 12119818a481SEtienne Carriere return res; 12129818a481SEtienne Carriere 12139818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 12149818a481SEtienne Carriere if (!bank) 12159818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 12169818a481SEtienne Carriere 1217bd03c8c3SGatien Chevallier if (compat->secure_extended) { 1218bd03c8c3SGatien Chevallier res = stm32_rifsc_check_tdcid(&bank->is_tdcid); 1219bd03c8c3SGatien Chevallier if (res) { 1220bd03c8c3SGatien Chevallier free(bank); 1221bd03c8c3SGatien Chevallier return res; 1222bd03c8c3SGatien Chevallier } 1223bd03c8c3SGatien Chevallier } 1224bd03c8c3SGatien Chevallier 12259818a481SEtienne Carriere /* 12269818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 12279818a481SEtienne Carriere * but consider also the "ranges" translation property 12289818a481SEtienne Carriere */ 12296a0116edSEtienne Carriere if (fdt_reg_info(fdt, node, &pa, &blen)) 12306a0116edSEtienne Carriere panic("missing reg or reg size property"); 12319818a481SEtienne Carriere 12329818a481SEtienne Carriere pa_va.pa = pa + range_offset; 12339818a481SEtienne Carriere 12349818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 12359818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 12369818a481SEtienne Carriere bank->clock = clk; 1237420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 1238b4893304SGatien Chevallier bank->sec_support = compat->secure_control; 12399818a481SEtienne Carriere 12409818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 12419818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 12429818a481SEtienne Carriere len /= sizeof(*cuint); 12439818a481SEtienne Carriere if (len % 4) 12449818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 12459818a481SEtienne Carriere 12469818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 12479818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 12489818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 12499818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 12509818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 12519818a481SEtienne Carriere cuint += 4; 12529818a481SEtienne Carriere } 12539818a481SEtienne Carriere 1254bd03c8c3SGatien Chevallier if (compat->secure_extended) { 1255bd03c8c3SGatien Chevallier /* RIF configuration */ 1256bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen); 1257bd03c8c3SGatien Chevallier 1258bd03c8c3SGatien Chevallier stm32_parse_gpio_rif_conf(bank, fdt, node); 1259bd03c8c3SGatien Chevallier } else if (bank->sec_support) { 1260bd03c8c3SGatien Chevallier /* Secure configuration */ 1261bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen); 1262bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", NULL); 1263bd03c8c3SGatien Chevallier if (cuint) 1264bd03c8c3SGatien Chevallier bank->seccfgr = fdt32_to_cpu(*cuint); 1265bd03c8c3SGatien Chevallier else 1266bd03c8c3SGatien Chevallier DMSG("GPIO bank %c assigned to non-secure", 1267bd03c8c3SGatien Chevallier bank->bank_id + 'A'); 1268bd03c8c3SGatien Chevallier } else { 1269bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_nsec(&pa_va, blen); 1270bd03c8c3SGatien Chevallier } 1271bd03c8c3SGatien Chevallier 12729818a481SEtienne Carriere *out_bank = bank; 1273bd03c8c3SGatien Chevallier 12749818a481SEtienne Carriere return TEE_SUCCESS; 12759818a481SEtienne Carriere } 12769818a481SEtienne Carriere 1277a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_firewall_register(const void *fdt, int node, 1278a650c9cbSEtienne Carriere struct stm32_gpio_bank *bank) 1279a650c9cbSEtienne Carriere { 1280a650c9cbSEtienne Carriere struct firewall_controller *controller = NULL; 1281a650c9cbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 1282a650c9cbSEtienne Carriere char bank_name[] = "gpio-bank-X"; 1283a650c9cbSEtienne Carriere char *name = NULL; 1284a650c9cbSEtienne Carriere 1285a650c9cbSEtienne Carriere if (!IS_ENABLED(CFG_DRIVERS_FIREWALL) || 1286a650c9cbSEtienne Carriere !bank->sec_support) 1287a650c9cbSEtienne Carriere return TEE_SUCCESS; 1288a650c9cbSEtienne Carriere 1289a650c9cbSEtienne Carriere controller = calloc(1, sizeof(*controller)); 1290a650c9cbSEtienne Carriere if (!controller) 1291a650c9cbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 1292a650c9cbSEtienne Carriere 1293a650c9cbSEtienne Carriere bank_name[sizeof(bank_name) - 2] = 'A' + bank->bank_id; 1294a650c9cbSEtienne Carriere name = strdup(bank_name); 1295a650c9cbSEtienne Carriere 1296a650c9cbSEtienne Carriere controller->name = name; 1297a650c9cbSEtienne Carriere controller->priv = bank; 1298a650c9cbSEtienne Carriere controller->ops = &stm32_gpio_firewall_ops; 1299a650c9cbSEtienne Carriere 1300a650c9cbSEtienne Carriere if (!controller->name) 1301a650c9cbSEtienne Carriere EMSG("Warning: out of memory to store bank name"); 1302a650c9cbSEtienne Carriere 1303a650c9cbSEtienne Carriere res = firewall_dt_controller_register(fdt, node, controller); 1304a650c9cbSEtienne Carriere if (res) { 1305a650c9cbSEtienne Carriere free(name); 1306a650c9cbSEtienne Carriere free(controller); 1307a650c9cbSEtienne Carriere } 1308a650c9cbSEtienne Carriere 1309a650c9cbSEtienne Carriere return res; 1310a650c9cbSEtienne Carriere } 1311a650c9cbSEtienne Carriere 1312bd03c8c3SGatien Chevallier /* Parse a pinctrl node to register the GPIO banks it describes */ 13130e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 13149818a481SEtienne Carriere const void *compat_data) 13159818a481SEtienne Carriere { 13169818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 13179818a481SEtienne Carriere const fdt32_t *cuint = NULL; 13189818a481SEtienne Carriere int range_offs = 0; 13199818a481SEtienne Carriere int b_node = 0; 13209818a481SEtienne Carriere int len = 0; 13219818a481SEtienne Carriere 13229818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 13239818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 13249818a481SEtienne Carriere if (!cuint) 13259818a481SEtienne Carriere panic("missing ranges property"); 13269818a481SEtienne Carriere 13279818a481SEtienne Carriere len /= sizeof(*cuint); 13289818a481SEtienne Carriere if (len == 3) 13299818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 13309818a481SEtienne Carriere 13319818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 13329818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 13339818a481SEtienne Carriere if (cuint) { 13349818a481SEtienne Carriere /* 13359818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 13369818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 13379818a481SEtienne Carriere * bank list. 13389818a481SEtienne Carriere */ 13399818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 13409818a481SEtienne Carriere 13419818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 13429818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 13439818a481SEtienne Carriere continue; 13449818a481SEtienne Carriere 13459818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 13469818a481SEtienne Carriere range_offs, &bank); 13479818a481SEtienne Carriere if (res) 13489818a481SEtienne Carriere return res; 13499818a481SEtienne Carriere 1350420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 1351420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 1352420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 1353420a32c5SEtienne Carriere if (res) 1354420a32c5SEtienne Carriere panic(); 1355420a32c5SEtienne Carriere 1356a650c9cbSEtienne Carriere res = stm32_gpio_firewall_register(fdt, b_node, bank); 1357a650c9cbSEtienne Carriere if (res) 1358a650c9cbSEtienne Carriere panic(); 1359a650c9cbSEtienne Carriere 13609818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 13619818a481SEtienne Carriere } else { 13629818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 13639818a481SEtienne Carriere panic(); 13649818a481SEtienne Carriere } 13659818a481SEtienne Carriere } 13669818a481SEtienne Carriere 13679818a481SEtienne Carriere return TEE_SUCCESS; 13689818a481SEtienne Carriere } 13699818a481SEtienne Carriere 1370b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 1371b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf) 1372b38386fbSEtienne Carriere { 1373b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv; 1374b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl; 1375430c415aSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 1376430c415aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 1377b38386fbSEtienne Carriere size_t pin_count = ref->count; 1378b38386fbSEtienne Carriere size_t n = 0; 1379430c415aSEtienne Carriere bool error = false; 1380430c415aSEtienne Carriere 1381430c415aSEtienne Carriere for (n = 0; n < pin_count; n++) { 1382430c415aSEtienne Carriere bank = stm32_gpio_get_bank(p[n].bank); 13835f27da69SEtienne Carriere 13845f27da69SEtienne Carriere if (!pin_is_accessible(bank, p[n].pin)) { 13855f27da69SEtienne Carriere EMSG("Apply pinctrl for pin %c%u that cannot be accessed", 13865f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin); 13875f27da69SEtienne Carriere error = true; 13885f27da69SEtienne Carriere continue; 13895f27da69SEtienne Carriere } 13905f27da69SEtienne Carriere 1391430c415aSEtienne Carriere res = acquire_rif_semaphore_if_needed(bank, p[n].pin); 1392430c415aSEtienne Carriere if (res) { 1393430c415aSEtienne Carriere EMSG("Failed to acquire GPIO %c%u semaphore", 1394430c415aSEtienne Carriere bank->bank_id + 'A', p[n].pin); 1395430c415aSEtienne Carriere error = true; 13965f27da69SEtienne Carriere continue; 13975f27da69SEtienne Carriere } 13985f27da69SEtienne Carriere 13995f27da69SEtienne Carriere if (p[n].cfg.nsec == !pin_is_secure(bank, p[n].pin)) 14005f27da69SEtienne Carriere continue; 14015f27da69SEtienne Carriere 14025f27da69SEtienne Carriere if (IS_ENABLED(CFG_INSECURE)) { 14035f27da69SEtienne Carriere IMSG("WARNING: apply pinctrl for %ssecure pin %c%u that is %ssecure", 14045f27da69SEtienne Carriere p[n].cfg.nsec ? "non-" : "", 14055f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin, 14065f27da69SEtienne Carriere pin_is_secure(bank, p[n].pin) ? "" : "non-"); 14075f27da69SEtienne Carriere } else { 14085f27da69SEtienne Carriere EMSG("Apply pinctrl for %ssecure pin %c%u that is %ssecure", 14095f27da69SEtienne Carriere p[n].cfg.nsec ? "non-" : "", 14105f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin, 14115f27da69SEtienne Carriere pin_is_secure(bank, p[n].pin) ? "" : "non-"); 14125f27da69SEtienne Carriere error = true; 1413430c415aSEtienne Carriere } 1414430c415aSEtienne Carriere } 1415430c415aSEtienne Carriere 1416430c415aSEtienne Carriere if (error) { 1417430c415aSEtienne Carriere for (n = 0; n < pin_count; n++) { 1418430c415aSEtienne Carriere bank = stm32_gpio_get_bank(p[n].bank); 1419430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, p[n].pin); 1420430c415aSEtienne Carriere } 1421430c415aSEtienne Carriere 1422430c415aSEtienne Carriere return TEE_ERROR_SECURITY; 1423430c415aSEtienne Carriere } 1424b38386fbSEtienne Carriere 1425b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++) 1426b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg); 1427b38386fbSEtienne Carriere 1428b38386fbSEtienne Carriere return TEE_SUCCESS; 1429b38386fbSEtienne Carriere } 1430b38386fbSEtienne Carriere 1431b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf) 1432b38386fbSEtienne Carriere { 1433b38386fbSEtienne Carriere free(conf); 1434b38386fbSEtienne Carriere } 1435b38386fbSEtienne Carriere 1436b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = { 1437b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply, 1438b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free, 1439b38386fbSEtienne Carriere }; 1440b38386fbSEtienne Carriere 1441b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops); 1442b38386fbSEtienne Carriere 144370ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl, 144470ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin, 144570ac0db5SEtienne Carriere unsigned int *count) 144670ac0db5SEtienne Carriere { 144770ac0db5SEtienne Carriere size_t conf_index = 0; 144870ac0db5SEtienne Carriere size_t pin_count = 0; 144970ac0db5SEtienne Carriere size_t n = 0; 145070ac0db5SEtienne Carriere 145170ac0db5SEtienne Carriere assert(count); 145270ac0db5SEtienne Carriere if (!pinctrl) 145370ac0db5SEtienne Carriere goto out; 145470ac0db5SEtienne Carriere 145570ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 145670ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 145770ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 145870ac0db5SEtienne Carriere 145970ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */ 146070ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 146170ac0db5SEtienne Carriere continue; 146270ac0db5SEtienne Carriere 146370ac0db5SEtienne Carriere if (bank || pin) { 146470ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) { 146570ac0db5SEtienne Carriere if (bank && pin_count < *count) 146670ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank; 146770ac0db5SEtienne Carriere if (pin && pin_count < *count) 146870ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin; 146970ac0db5SEtienne Carriere pin_count++; 147070ac0db5SEtienne Carriere } 147170ac0db5SEtienne Carriere } else { 147270ac0db5SEtienne Carriere pin_count += ref->count; 147370ac0db5SEtienne Carriere } 147470ac0db5SEtienne Carriere } 147570ac0db5SEtienne Carriere 147670ac0db5SEtienne Carriere out: 147770ac0db5SEtienne Carriere *count = pin_count; 147870ac0db5SEtienne Carriere } 147970ac0db5SEtienne Carriere 1480b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */ 1481b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs, 1482b38386fbSEtienne Carriere void *data __unused, 1483b38386fbSEtienne Carriere struct pinconf **out_pinconf) 1484b38386fbSEtienne Carriere { 1485b38386fbSEtienne Carriere struct conf { 1486b38386fbSEtienne Carriere struct pinconf pinconf; 1487b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref; 1488b38386fbSEtienne Carriere } *loc_conf = NULL; 1489b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL; 1490b38386fbSEtienne Carriere struct pinconf *pinconf = NULL; 1491b38386fbSEtienne Carriere const void *fdt = NULL; 1492b38386fbSEtienne Carriere size_t pin_count = 0; 1493b38386fbSEtienne Carriere int pinctrl_node = 0; 1494b38386fbSEtienne Carriere int pinmux_node = 0; 1495b38386fbSEtienne Carriere int count = 0; 1496b38386fbSEtienne Carriere 1497b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node; 1498b38386fbSEtienne Carriere fdt = pargs->fdt; 1499b38386fbSEtienne Carriere assert(fdt && pinctrl_node); 1500b38386fbSEtienne Carriere 1501b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 1502b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count)) 1503b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t); 1504b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND) 1505b38386fbSEtienne Carriere panic(); 1506b38386fbSEtienne Carriere } 1507b38386fbSEtienne Carriere 1508b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count); 1509b38386fbSEtienne Carriere if (!loc_conf) 1510b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 1511b38386fbSEtienne Carriere 1512b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf; 1513b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops; 1514b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref; 1515b38386fbSEtienne Carriere 1516b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count; 1517b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl; 1518b38386fbSEtienne Carriere 1519b38386fbSEtienne Carriere count = 0; 1520b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 1521b38386fbSEtienne Carriere int found = 0; 1522b38386fbSEtienne Carriere 15235f27da69SEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node, 15245f27da69SEtienne Carriere pargs->consumer_node, 15255f27da69SEtienne Carriere pinctrl + count, 1526b38386fbSEtienne Carriere pin_count - count); 1527b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) { 1528b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */ 1529b38386fbSEtienne Carriere panic(); 1530b38386fbSEtienne Carriere } 1531b38386fbSEtienne Carriere 1532b38386fbSEtienne Carriere count += found; 1533b38386fbSEtienne Carriere } 1534b38386fbSEtienne Carriere 1535b38386fbSEtienne Carriere *out_pinconf = pinconf; 1536b38386fbSEtienne Carriere 1537b38386fbSEtienne Carriere return TEE_SUCCESS; 1538b38386fbSEtienne Carriere } 1539b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 1540b38386fbSEtienne Carriere 1541bfc43b68SGatien Chevallier static void stm32_gpio_get_conf_sec(struct stm32_gpio_bank *bank) 1542bfc43b68SGatien Chevallier { 1543bfc43b68SGatien Chevallier if (bank->sec_support) { 1544bfc43b68SGatien Chevallier clk_enable(bank->clock); 1545bfc43b68SGatien Chevallier bank->seccfgr = io_read32(bank->base + GPIO_SECR_OFFSET); 1546bfc43b68SGatien Chevallier clk_disable(bank->clock); 1547bfc43b68SGatien Chevallier } 1548bfc43b68SGatien Chevallier } 1549bfc43b68SGatien Chevallier 1550bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank) 1551bd03c8c3SGatien Chevallier { 1552bd03c8c3SGatien Chevallier if (bank->sec_support) { 1553bd03c8c3SGatien Chevallier clk_enable(bank->clock); 1554bd03c8c3SGatien Chevallier io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr); 1555bd03c8c3SGatien Chevallier clk_disable(bank->clock); 1556bd03c8c3SGatien Chevallier } 1557bd03c8c3SGatien Chevallier } 1558bd03c8c3SGatien Chevallier 1559bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_resume(void) 1560bfc43b68SGatien Chevallier { 1561bfc43b68SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 1562bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = NULL; 1563bfc43b68SGatien Chevallier 1564bfc43b68SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) { 1565bfc43b68SGatien Chevallier if (bank->rif_cfg) { 1566bfc43b68SGatien Chevallier if (!bank->is_tdcid) 1567bfc43b68SGatien Chevallier continue; 1568bfc43b68SGatien Chevallier 1569bfc43b68SGatien Chevallier bank->rif_cfg->access_mask[0] = GENMASK_32(bank->ngpios, 1570bfc43b68SGatien Chevallier 0); 1571bfc43b68SGatien Chevallier 1572a72f07daSEtienne Carriere res = apply_rif_config(bank, 1573a72f07daSEtienne Carriere bank->rif_cfg->access_mask[0]); 1574bfc43b68SGatien Chevallier if (res) { 1575bfc43b68SGatien Chevallier EMSG("Failed to set GPIO bank %c RIF config", 1576bfc43b68SGatien Chevallier 'A' + bank->bank_id); 1577bfc43b68SGatien Chevallier return res; 1578bfc43b68SGatien Chevallier } 1579bfc43b68SGatien Chevallier } else { 1580bfc43b68SGatien Chevallier stm32_gpio_set_conf_sec(bank); 1581bfc43b68SGatien Chevallier } 1582bfc43b68SGatien Chevallier } 1583bfc43b68SGatien Chevallier 1584bfc43b68SGatien Chevallier return TEE_SUCCESS; 1585bfc43b68SGatien Chevallier } 1586bfc43b68SGatien Chevallier 1587bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_suspend(void) 1588bfc43b68SGatien Chevallier { 1589bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = NULL; 1590bfc43b68SGatien Chevallier 1591bfc43b68SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) { 1592bfc43b68SGatien Chevallier if (bank->rif_cfg) { 1593bfc43b68SGatien Chevallier if (bank->is_tdcid) 1594bfc43b68SGatien Chevallier stm32_gpio_save_rif_config(bank); 1595bfc43b68SGatien Chevallier } else { 1596bfc43b68SGatien Chevallier stm32_gpio_get_conf_sec(bank); 1597bfc43b68SGatien Chevallier } 1598bfc43b68SGatien Chevallier } 1599bfc43b68SGatien Chevallier 1600bfc43b68SGatien Chevallier return TEE_SUCCESS; 1601bfc43b68SGatien Chevallier } 1602bfc43b68SGatien Chevallier 1603bfc43b68SGatien Chevallier static TEE_Result 1604bfc43b68SGatien Chevallier stm32_gpio_sec_config_pm(enum pm_op op, unsigned int pm_hint, 1605bfc43b68SGatien Chevallier const struct pm_callback_handle *hdl __unused) 1606bfc43b68SGatien Chevallier { 1607bfc43b68SGatien Chevallier TEE_Result ret = TEE_ERROR_GENERIC; 1608bfc43b68SGatien Chevallier 1609bfc43b68SGatien Chevallier if (!PM_HINT_IS_STATE(pm_hint, CONTEXT)) 1610bfc43b68SGatien Chevallier return TEE_SUCCESS; 1611bfc43b68SGatien Chevallier 1612bfc43b68SGatien Chevallier if (op == PM_OP_RESUME) 1613bfc43b68SGatien Chevallier ret = stm32_gpio_sec_config_resume(); 1614bfc43b68SGatien Chevallier else 1615bfc43b68SGatien Chevallier ret = stm32_gpio_sec_config_suspend(); 1616bfc43b68SGatien Chevallier 1617bfc43b68SGatien Chevallier return ret; 1618bfc43b68SGatien Chevallier } 1619bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(stm32_gpio_sec_config_pm); 1620bfc43b68SGatien Chevallier 1621bd03c8c3SGatien Chevallier /* 1622bd03c8c3SGatien Chevallier * Several pinctrl nodes can be probed. Their bank will be put in the unique 1623bd03c8c3SGatien Chevallier * bank_list. To avoid multiple configuration set for a bank when looping 1624bd03c8c3SGatien Chevallier * over each bank in the bank list, ready is set to true when a bank is 1625bd03c8c3SGatien Chevallier * configured. Therefore, during other bank probes, the configuration won't 1626bd03c8c3SGatien Chevallier * be set again. 1627bd03c8c3SGatien Chevallier */ 1628bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void) 1629bd03c8c3SGatien Chevallier { 1630bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 1631bd03c8c3SGatien Chevallier struct stm32_gpio_bank *bank = NULL; 1632430c415aSEtienne Carriere unsigned int pin = 0; 1633bd03c8c3SGatien Chevallier 1634bd03c8c3SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) { 1635bd03c8c3SGatien Chevallier if (bank->ready) 1636bd03c8c3SGatien Chevallier continue; 1637bd03c8c3SGatien Chevallier 1638bd03c8c3SGatien Chevallier if (bank->rif_cfg) { 1639a72f07daSEtienne Carriere res = apply_rif_config(bank, 1640a72f07daSEtienne Carriere bank->rif_cfg->access_mask[0]); 1641bd03c8c3SGatien Chevallier if (res) { 1642bd03c8c3SGatien Chevallier EMSG("Failed to set GPIO bank %c RIF config", 1643bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 1644bd03c8c3SGatien Chevallier STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank, 1645bd03c8c3SGatien Chevallier link); 16469def1fb7SGatien Chevallier free(bank); 1647bd03c8c3SGatien Chevallier return res; 1648bd03c8c3SGatien Chevallier } 1649430c415aSEtienne Carriere 1650430c415aSEtienne Carriere /* 1651430c415aSEtienne Carriere * Semaphores for pinctrl and GPIO are taken when 1652430c415aSEtienne Carriere * these are used (pinctrl state applied, GPIO 1653430c415aSEtienne Carriere * consumed) or when an explicit firewall configuration 1654430c415aSEtienne Carriere * is requested through the firewall framework. 1655430c415aSEtienne Carriere * Therefore release here the taken semaphores. 1656430c415aSEtienne Carriere */ 1657430c415aSEtienne Carriere for (pin = 0; pin < bank->ngpios; pin++) 1658430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, pin); 1659430c415aSEtienne Carriere 1660bd03c8c3SGatien Chevallier } else { 1661bd03c8c3SGatien Chevallier stm32_gpio_set_conf_sec(bank); 1662bd03c8c3SGatien Chevallier } 1663bd03c8c3SGatien Chevallier 1664bd03c8c3SGatien Chevallier bank->ready = true; 1665bd03c8c3SGatien Chevallier } 1666bd03c8c3SGatien Chevallier 1667bd03c8c3SGatien Chevallier return TEE_SUCCESS; 1668bd03c8c3SGatien Chevallier } 1669bd03c8c3SGatien Chevallier 16700e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 16710e0435e2SEtienne Carriere const void *compat_data) 16720e0435e2SEtienne Carriere { 1673bfc43b68SGatien Chevallier static bool pm_register; 1674b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 1675b38386fbSEtienne Carriere 16760e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 1677b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data); 1678b38386fbSEtienne Carriere if (res) 1679b38386fbSEtienne Carriere return res; 1680b38386fbSEtienne Carriere 1681bd03c8c3SGatien Chevallier if (STAILQ_EMPTY(&bank_list)) 1682bd03c8c3SGatien Chevallier DMSG("no gpio bank for that driver"); 1683bd03c8c3SGatien Chevallier else if (apply_sec_cfg()) 1684bd03c8c3SGatien Chevallier panic(); 1685bd03c8c3SGatien Chevallier 1686bfc43b68SGatien Chevallier if (!pm_register) { 1687bfc43b68SGatien Chevallier /* 1688bfc43b68SGatien Chevallier * Register to PM once for all probed banks to restore 1689bfc43b68SGatien Chevallier * their secure configuration. 1690bfc43b68SGatien Chevallier */ 1691bfc43b68SGatien Chevallier register_pm_driver_cb(stm32_gpio_sec_config_pm, NULL, 1692bfc43b68SGatien Chevallier "stm32-gpio-secure-config"); 1693bfc43b68SGatien Chevallier pm_register = true; 1694bfc43b68SGatien Chevallier } 1695bfc43b68SGatien Chevallier 1696b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 1697b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get, 1698b38386fbSEtienne Carriere (void *)compat_data); 1699b38386fbSEtienne Carriere if (res) 1700bd03c8c3SGatien Chevallier panic(); 1701b38386fbSEtienne Carriere #endif 1702b38386fbSEtienne Carriere 1703b38386fbSEtienne Carriere return TEE_SUCCESS; 17040e0435e2SEtienne Carriere } 17050e0435e2SEtienne Carriere 17060e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 1707e569f6adSEtienne Carriere { 1708e569f6adSEtienne Carriere .compatible = "st,stm32mp135-pinctrl", 1709b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1710b4893304SGatien Chevallier .secure_control = true, 1711bd03c8c3SGatien Chevallier .secure_extended = false, 1712b4893304SGatien Chevallier }, 1713e569f6adSEtienne Carriere }, 1714e569f6adSEtienne Carriere { 1715e569f6adSEtienne Carriere .compatible = "st,stm32mp157-pinctrl", 1716b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1717b4893304SGatien Chevallier .secure_control = false, 1718bd03c8c3SGatien Chevallier .secure_extended = false, 1719b4893304SGatien Chevallier }, 1720e569f6adSEtienne Carriere }, 1721e569f6adSEtienne Carriere { 1722e569f6adSEtienne Carriere .compatible = "st,stm32mp157-z-pinctrl", 1723b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1724b4893304SGatien Chevallier .gpioz = true, 1725b4893304SGatien Chevallier .secure_control = true, 1726bd03c8c3SGatien Chevallier .secure_extended = false, 1727bd03c8c3SGatien Chevallier }, 1728bd03c8c3SGatien Chevallier }, 1729bd03c8c3SGatien Chevallier { 1730bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-pinctrl", 1731bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){ 1732bd03c8c3SGatien Chevallier .secure_control = true, 1733bd03c8c3SGatien Chevallier .secure_extended = true, 1734bd03c8c3SGatien Chevallier }, 1735bd03c8c3SGatien Chevallier }, 1736bd03c8c3SGatien Chevallier { 1737bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-z-pinctrl", 1738bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){ 1739bd03c8c3SGatien Chevallier .gpioz = true, 1740bd03c8c3SGatien Chevallier .secure_control = true, 1741bd03c8c3SGatien Chevallier .secure_extended = true, 1742b4893304SGatien Chevallier }, 1743e569f6adSEtienne Carriere }, 17440e0435e2SEtienne Carriere { } 17450e0435e2SEtienne Carriere }; 17460e0435e2SEtienne Carriere 17470e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 17480e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 17490e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 17500e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 17510e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 17520e0435e2SEtienne Carriere }; 1753