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> 18*5f27da69SEtienne 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 341001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 351001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 361001585eSEtienne Carriere #endif 371001585eSEtienne Carriere 384b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 394b5e93edSEtienne Carriere 405eed568cSGatien Chevallier #define GPIO_MODER_OFFSET U(0x00) 415eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET U(0x04) 425eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET U(0x08) 435eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET U(0x0c) 445eed568cSGatien Chevallier #define GPIO_IDR_OFFSET U(0x10) 455eed568cSGatien Chevallier #define GPIO_ODR_OFFSET U(0x14) 465eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET U(0x18) 475eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET U(0x20) 485eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET U(0x24) 495eed568cSGatien Chevallier #define GPIO_SECR_OFFSET U(0x30) 50bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET U(0x34) 51bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET U(0x38) 52bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x) (U(0x50) + U(0x8) * (x)) 53bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x) (U(0x54) + U(0x8) * (x)) 544b5e93edSEtienne Carriere 555eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT U(0x8) 564b5e93edSEtienne Carriere 57bd03c8c3SGatien Chevallier /* 58bd03c8c3SGatien Chevallier * CIDCFGR register bitfields 59bd03c8c3SGatien Chevallier */ 60bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK GENMASK_32(23, 16) 61bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK GENMASK_32(6, 4) 62bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK (_CIDCFGR_CFEN | _CIDCFGR_SEMEN | \ 63bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SCID_MASK | \ 64bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SEMWL_MASK) 65bd03c8c3SGatien Chevallier 66bd03c8c3SGatien Chevallier /* 67bd03c8c3SGatien Chevallier * PRIVCFGR register bitfields 68bd03c8c3SGatien Chevallier */ 69bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK GENMASK_32(15, 0) 70bd03c8c3SGatien Chevallier 71bd03c8c3SGatien Chevallier /* 72bd03c8c3SGatien Chevallier * SECCFGR register bitfields 73bd03c8c3SGatien Chevallier */ 74bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK GENMASK_32(15, 0) 75bd03c8c3SGatien Chevallier 76bd03c8c3SGatien Chevallier /* 77bd03c8c3SGatien Chevallier * RCFGLOCKR register bitfields 78bd03c8c3SGatien Chevallier */ 79bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK GENMASK_32(15, 0) 80bd03c8c3SGatien Chevallier 81bd03c8c3SGatien Chevallier /* 82bd03c8c3SGatien Chevallier * SEMCR register bitfields 83bd03c8c3SGatien Chevallier */ 84bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M GENMASK_32(6, 4) 85bd03c8c3SGatien Chevallier 864b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 874b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 884b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 89729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 904b5e93edSEtienne Carriere 915eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT U(12) 924b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 935eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT U(8) 944b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 954b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 964b5e93edSEtienne Carriere 979818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 989818a481SEtienne Carriere 9969715ce9SEtienne Carriere #define GPIO_MODE_INPUT U(0x0) 10069715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT U(0x1) 10169715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE U(0x2) 10269715ce9SEtienne Carriere #define GPIO_MODE_ANALOG U(0x3) 10369715ce9SEtienne Carriere 10469715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL U(0x0) 10569715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN U(0x1) 10669715ce9SEtienne Carriere 10769715ce9SEtienne Carriere #define GPIO_OSPEED_LOW U(0x0) 10869715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM U(0x1) 10969715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH U(0x2) 11069715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH U(0x3) 11169715ce9SEtienne Carriere 11269715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL U(0x0) 11369715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP U(0x1) 11469715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN U(0x2) 11569715ce9SEtienne Carriere 11669715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW U(0x0) 11769715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH U(0x1) 11869715ce9SEtienne Carriere 119bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED U(3) 120bd03c8c3SGatien Chevallier 12169715ce9SEtienne Carriere /* 12269715ce9SEtienne Carriere * GPIO configuration description structured as single 16bit word 12369715ce9SEtienne Carriere * for efficient save/restore when GPIO pin suspends or resumes. 12469715ce9SEtienne Carriere * 12569715ce9SEtienne Carriere * @mode: One of GPIO_MODE_* 12669715ce9SEtienne Carriere * @otype: One of GPIO_OTYPE_* 12769715ce9SEtienne Carriere * @ospeed: One of GPIO_OSPEED_* 12869715ce9SEtienne Carriere * @pupd: One of GPIO_PUPD_* 12969715ce9SEtienne Carriere * @od: One of GPIO_OD_* 13069715ce9SEtienne Carriere * @af: Alternate function numerical ID between 0 and 15 131*5f27da69SEtienne Carriere * @nsec: Hint on expected secure state of the pin: 0 if secure, 1 otherwise 13269715ce9SEtienne Carriere */ 13369715ce9SEtienne Carriere struct gpio_cfg { 13469715ce9SEtienne Carriere uint16_t mode: 2; 13569715ce9SEtienne Carriere uint16_t otype: 1; 13669715ce9SEtienne Carriere uint16_t ospeed: 2; 13769715ce9SEtienne Carriere uint16_t pupd: 2; 13869715ce9SEtienne Carriere uint16_t od: 1; 13969715ce9SEtienne Carriere uint16_t af: 4; 140*5f27da69SEtienne Carriere uint16_t nsec: 1; 14169715ce9SEtienne Carriere }; 14269715ce9SEtienne Carriere 14369715ce9SEtienne Carriere /* 14469715ce9SEtienne Carriere * Description of a pin and its muxing 14569715ce9SEtienne Carriere * 14669715ce9SEtienne Carriere * @bank: GPIO bank identifier as assigned by the platform 14769715ce9SEtienne Carriere * @pin: Pin number in the GPIO bank 14869715ce9SEtienne Carriere * @cfg: Pin configuration 14969715ce9SEtienne Carriere */ 15069715ce9SEtienne Carriere struct stm32_pinctrl { 15169715ce9SEtienne Carriere uint8_t bank; 15269715ce9SEtienne Carriere uint8_t pin; 15369715ce9SEtienne Carriere struct gpio_cfg cfg; 15469715ce9SEtienne Carriere }; 15569715ce9SEtienne Carriere 156b38386fbSEtienne Carriere /* 157b38386fbSEtienne Carriere * struct stm32_pinctrl_array - Array of pins in a pin control state 158b38386fbSEtienne Carriere * @count: Number of cells in @pinctrl 159b38386fbSEtienne Carriere * @pinctrl: Pin control configuration 160b38386fbSEtienne Carriere */ 161b38386fbSEtienne Carriere struct stm32_pinctrl_array { 162b38386fbSEtienne Carriere size_t count; 163b38386fbSEtienne Carriere struct stm32_pinctrl pinctrl[]; 164b38386fbSEtienne Carriere }; 165b38386fbSEtienne Carriere 1669818a481SEtienne Carriere /** 1679818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 1689818a481SEtienne Carriere * 1699818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 1709818a481SEtienne Carriere * @clock: clock identifier. 171420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 1729818a481SEtienne Carriere * @ngpios: number of GPIOs. 1739818a481SEtienne Carriere * @bank_id: Id of the bank. 1749818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 175bd03c8c3SGatien Chevallier * @rif_cfg: RIF configuration data 176bd03c8c3SGatien Chevallier * @seccfgr: non-RIF bank secure configuration data 177bd03c8c3SGatien Chevallier * @sec_support: True if bank supports pin security protection, else false 178bd03c8c3SGatien Chevallier * @ready: True if configuration is applied, else false 179bd03c8c3SGatien Chevallier * @is_tdcid: True if OP-TEE runs as Trusted Domain CID 1809818a481SEtienne Carriere * @link: Link in bank list 1819818a481SEtienne Carriere */ 1829818a481SEtienne Carriere struct stm32_gpio_bank { 1839818a481SEtienne Carriere vaddr_t base; 1849818a481SEtienne Carriere struct clk *clock; 185420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 1869818a481SEtienne Carriere unsigned int ngpios; 1879818a481SEtienne Carriere unsigned int bank_id; 1889818a481SEtienne Carriere unsigned int lock; 189bd03c8c3SGatien Chevallier struct rif_conf_data *rif_cfg; 190bd03c8c3SGatien Chevallier uint32_t seccfgr; 191b4893304SGatien Chevallier bool sec_support; 192bd03c8c3SGatien Chevallier bool ready; 193bd03c8c3SGatien Chevallier bool is_tdcid; 1949818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 1959818a481SEtienne Carriere }; 1969818a481SEtienne Carriere 197bfc43b68SGatien Chevallier /* 198bfc43b68SGatien Chevallier * struct stm32_gpio_pm_state - Consumed GPIO for PM purpose 199bfc43b68SGatien Chevallier * @gpio_pinctrl: Reference and configuration state for a consumed GPIO 200bfc43b68SGatien Chevallier * @level: GPIO level 201bfc43b68SGatien Chevallier * @link: Link in consumed GPIO list 202bfc43b68SGatien Chevallier */ 203bfc43b68SGatien Chevallier struct stm32_gpio_pm_state { 204bfc43b68SGatien Chevallier struct stm32_pinctrl gpio_pinctrl; 205bfc43b68SGatien Chevallier uint8_t level; 206bfc43b68SGatien Chevallier SLIST_ENTRY(stm32_gpio_pm_state) link; 207bfc43b68SGatien Chevallier }; 208bfc43b68SGatien Chevallier 209b4893304SGatien Chevallier /** 210e569f6adSEtienne Carriere * Compatibility information of supported banks 211b4893304SGatien Chevallier * 212b4893304SGatien Chevallier * @gpioz: True if bank is a GPIOZ bank 213b4893304SGatien Chevallier * @secure_control: Identify GPIO security bank capability. 214bd03c8c3SGatien Chevallier * @secure_extended: Identify RIF presence. 215e569f6adSEtienne Carriere */ 216e569f6adSEtienne Carriere struct bank_compat { 217e569f6adSEtienne Carriere bool gpioz; 218b4893304SGatien Chevallier bool secure_control; 219bd03c8c3SGatien Chevallier bool secure_extended; 220e569f6adSEtienne Carriere }; 221e569f6adSEtienne Carriere 2224b5e93edSEtienne Carriere static unsigned int gpio_lock; 2234b5e93edSEtienne Carriere 2249818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 2259818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 2269818a481SEtienne Carriere 227bfc43b68SGatien Chevallier static SLIST_HEAD(, stm32_gpio_pm_state) consumed_gpios_head; 228bfc43b68SGatien Chevallier 229420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 230420a32c5SEtienne Carriere 231420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 232420a32c5SEtienne Carriere { 233420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 234420a32c5SEtienne Carriere } 235420a32c5SEtienne Carriere 236420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 237420a32c5SEtienne Carriere unsigned int gpio_pin) 238420a32c5SEtienne Carriere { 239420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 240420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 241420a32c5SEtienne Carriere unsigned int reg_offset = 0; 242420a32c5SEtienne Carriere unsigned int mode = 0; 243420a32c5SEtienne Carriere 244420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2452fd102ebSEtienne Carriere 2462fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2472fd102ebSEtienne Carriere panic(); 248420a32c5SEtienne Carriere 249420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 250420a32c5SEtienne Carriere GPIO_MODE_MASK; 251420a32c5SEtienne Carriere 252420a32c5SEtienne Carriere switch (mode) { 253420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 254420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 255420a32c5SEtienne Carriere break; 256420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 257420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 258420a32c5SEtienne Carriere break; 259420a32c5SEtienne Carriere default: 260420a32c5SEtienne Carriere panic(); 261420a32c5SEtienne Carriere } 262420a32c5SEtienne Carriere 263420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 264420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 265420a32c5SEtienne Carriere else 266420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 267420a32c5SEtienne Carriere 268420a32c5SEtienne Carriere clk_disable(bank->clock); 269420a32c5SEtienne Carriere 270420a32c5SEtienne Carriere return level; 271420a32c5SEtienne Carriere } 272420a32c5SEtienne Carriere 273420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 274420a32c5SEtienne Carriere enum gpio_level level) 275420a32c5SEtienne Carriere { 276420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 277420a32c5SEtienne Carriere 278420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2792fd102ebSEtienne Carriere 2802fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2812fd102ebSEtienne Carriere panic(); 282420a32c5SEtienne Carriere 283420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 284420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 285420a32c5SEtienne Carriere 286420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 287420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 288420a32c5SEtienne Carriere else 289420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 290420a32c5SEtienne Carriere 291420a32c5SEtienne Carriere clk_disable(bank->clock); 292420a32c5SEtienne Carriere } 293420a32c5SEtienne Carriere 294420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 295420a32c5SEtienne Carriere unsigned int gpio_pin) 296420a32c5SEtienne Carriere { 297420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 298420a32c5SEtienne Carriere uint32_t mode = 0; 299420a32c5SEtienne Carriere 300420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 3012fd102ebSEtienne Carriere 3022fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 3032fd102ebSEtienne Carriere panic(); 304420a32c5SEtienne Carriere 305420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 306420a32c5SEtienne Carriere GPIO_MODE_MASK; 307420a32c5SEtienne Carriere 308420a32c5SEtienne Carriere clk_disable(bank->clock); 309420a32c5SEtienne Carriere 310420a32c5SEtienne Carriere switch (mode) { 311420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 312420a32c5SEtienne Carriere return GPIO_DIR_IN; 313420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 314420a32c5SEtienne Carriere return GPIO_DIR_OUT; 315420a32c5SEtienne Carriere default: 316420a32c5SEtienne Carriere panic(); 317420a32c5SEtienne Carriere } 318420a32c5SEtienne Carriere } 319420a32c5SEtienne Carriere 320420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 321420a32c5SEtienne Carriere unsigned int gpio_pin, 322420a32c5SEtienne Carriere enum gpio_dir direction) 323420a32c5SEtienne Carriere { 324420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 325420a32c5SEtienne Carriere uint32_t exceptions = 0; 326420a32c5SEtienne Carriere uint32_t mode = 0; 327420a32c5SEtienne Carriere 328420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 329420a32c5SEtienne Carriere 330420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 331420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 332420a32c5SEtienne Carriere else 333420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 334420a32c5SEtienne Carriere 3352fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 3362fd102ebSEtienne Carriere panic(); 337420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 338420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 339420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 340420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 341420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 342420a32c5SEtienne Carriere clk_disable(bank->clock); 343420a32c5SEtienne Carriere } 344420a32c5SEtienne Carriere 345bfc43b68SGatien Chevallier /* Forward reference to the PM callback handler for consumed GPIOs */ 346bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, unsigned int pm_hint, 347bfc43b68SGatien Chevallier const struct pm_callback_handle *pm_hdl); 348bfc43b68SGatien Chevallier 349430c415aSEtienne Carriere /* Forward reference to RIF semaphore release helper function */ 350430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank, 351430c415aSEtienne Carriere unsigned int pin); 352430c415aSEtienne Carriere 353bfc43b68SGatien Chevallier static void stm32_gpio_put_gpio(struct gpio_chip *chip, struct gpio *gpio) 354420a32c5SEtienne Carriere { 355bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 356bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *tstate = NULL; 357bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *state = NULL; 358bfc43b68SGatien Chevallier uint32_t exceptions = 0; 359bfc43b68SGatien Chevallier 360420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 361bfc43b68SGatien Chevallier 362bfc43b68SGatien Chevallier exceptions = cpu_spin_lock_xsave(&gpio_lock); 363bfc43b68SGatien Chevallier 364bfc43b68SGatien Chevallier SLIST_FOREACH_SAFE(state, &consumed_gpios_head, link, tstate) { 365bfc43b68SGatien Chevallier if (state->gpio_pinctrl.bank == bank->bank_id && 366bfc43b68SGatien Chevallier state->gpio_pinctrl.pin == gpio->pin) { 367bfc43b68SGatien Chevallier SLIST_REMOVE(&consumed_gpios_head, state, 368bfc43b68SGatien Chevallier stm32_gpio_pm_state, link); 369bfc43b68SGatien Chevallier unregister_pm_driver_cb(consumed_gpios_pm, state); 370430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, gpio->pin); 371bfc43b68SGatien Chevallier free(state); 372420a32c5SEtienne Carriere free(gpio); 373bfc43b68SGatien Chevallier break; 374bfc43b68SGatien Chevallier } 375bfc43b68SGatien Chevallier } 376bfc43b68SGatien Chevallier assert(state); 377bfc43b68SGatien Chevallier 378bfc43b68SGatien Chevallier cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 379420a32c5SEtienne Carriere } 380420a32c5SEtienne Carriere 381420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 382420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 383420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 384420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 385420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 386420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 387420a32c5SEtienne Carriere }; 388420a32c5SEtienne Carriere 389420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 390420a32c5SEtienne Carriere { 391420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 392420a32c5SEtienne Carriere } 393420a32c5SEtienne Carriere 394077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 3954b5e93edSEtienne Carriere { 396077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 3974b5e93edSEtienne Carriere 398077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 399077d486eSEtienne Carriere if (bank_id == bank->bank_id) 400077d486eSEtienne Carriere return bank; 401077d486eSEtienne Carriere 402077d486eSEtienne Carriere panic(); 403077d486eSEtienne Carriere } 404077d486eSEtienne Carriere 405430c415aSEtienne Carriere #if defined(CFG_STM32_RIF) 4064675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank, unsigned int pin) 4074675225eSEtienne Carriere { 4084675225eSEtienne Carriere bool accessible = false; 4094675225eSEtienne Carriere uint32_t cidcfgr = 0; 4104675225eSEtienne Carriere 4114675225eSEtienne Carriere if (!bank->rif_cfg) 4124675225eSEtienne Carriere return true; 4134675225eSEtienne Carriere 4144675225eSEtienne Carriere if (clk_enable(bank->clock)) 4154675225eSEtienne Carriere panic(); 4164675225eSEtienne Carriere 4174675225eSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin)); 4184675225eSEtienne Carriere 4194675225eSEtienne Carriere if (!(cidcfgr & _CIDCFGR_CFEN)) { 4204675225eSEtienne Carriere /* Resource can be accessed when CID filtering is disabled */ 4214675225eSEtienne Carriere accessible = true; 4224675225eSEtienne Carriere } else if (stm32_rif_scid_ok(cidcfgr, GPIO_CIDCFGR_SCID_MASK, 4234675225eSEtienne Carriere RIF_CID1)) { 4244675225eSEtienne Carriere /* Resource can be accessed if CID1 is statically allowed */ 4254675225eSEtienne Carriere accessible = true; 4264675225eSEtienne Carriere } else if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) { 4274675225eSEtienne Carriere /* CID1 is allowed to request the semaphore */ 4284675225eSEtienne Carriere accessible = true; 4294675225eSEtienne Carriere } 4304675225eSEtienne Carriere 4314675225eSEtienne Carriere clk_disable(bank->clock); 4324675225eSEtienne Carriere 4334675225eSEtienne Carriere return accessible; 4344675225eSEtienne Carriere } 4354675225eSEtienne Carriere 436430c415aSEtienne Carriere static TEE_Result acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank, 437430c415aSEtienne Carriere unsigned int pin) 438430c415aSEtienne Carriere { 439430c415aSEtienne Carriere TEE_Result res = TEE_SUCCESS; 440430c415aSEtienne Carriere uint32_t cidcfgr = 0; 441430c415aSEtienne Carriere 442430c415aSEtienne Carriere if (!bank->rif_cfg) 443430c415aSEtienne Carriere return TEE_SUCCESS; 444430c415aSEtienne Carriere 445430c415aSEtienne Carriere res = clk_enable(bank->clock); 446430c415aSEtienne Carriere if (res) 447430c415aSEtienne Carriere return res; 448430c415aSEtienne Carriere 449430c415aSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin)); 450430c415aSEtienne Carriere 451430c415aSEtienne Carriere if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) 452430c415aSEtienne Carriere res = stm32_rif_acquire_semaphore(bank->base + GPIO_SEMCR(pin), 453430c415aSEtienne Carriere GPIO_MAX_CID_SUPPORTED); 454430c415aSEtienne Carriere 455430c415aSEtienne Carriere clk_disable(bank->clock); 456430c415aSEtienne Carriere 457430c415aSEtienne Carriere return res; 458430c415aSEtienne Carriere } 459430c415aSEtienne Carriere 460430c415aSEtienne Carriere static uint32_t semaphore_current_cid(struct stm32_gpio_bank *bank, 461430c415aSEtienne Carriere unsigned int pin) 462430c415aSEtienne Carriere { 463430c415aSEtienne Carriere return (io_read32(bank->base + GPIO_SEMCR(pin)) >> 464430c415aSEtienne Carriere _CIDCFGR_SCID_SHIFT) & 465430c415aSEtienne Carriere GENMASK_32(GPIO_MAX_CID_SUPPORTED - 1, 0); 466430c415aSEtienne Carriere } 467430c415aSEtienne Carriere 468430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank, 469430c415aSEtienne Carriere unsigned int pin) 470430c415aSEtienne Carriere { 471430c415aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 472430c415aSEtienne Carriere uint32_t cidcfgr = 0; 473430c415aSEtienne Carriere 474430c415aSEtienne Carriere if (!bank->rif_cfg) 475430c415aSEtienne Carriere return; 476430c415aSEtienne Carriere 477430c415aSEtienne Carriere res = clk_enable(bank->clock); 478430c415aSEtienne Carriere if (res) 479430c415aSEtienne Carriere panic(); 480430c415aSEtienne Carriere 481430c415aSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin)); 482430c415aSEtienne Carriere 483430c415aSEtienne Carriere if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1) && 484430c415aSEtienne Carriere semaphore_current_cid(bank, pin) == RIF_CID1) { 485430c415aSEtienne Carriere res = stm32_rif_release_semaphore(bank->base + GPIO_SEMCR(pin), 486430c415aSEtienne Carriere GPIO_MAX_CID_SUPPORTED); 487430c415aSEtienne Carriere if (res) { 488430c415aSEtienne Carriere EMSG("Failed to release GPIO %c%u semaphore", 489430c415aSEtienne Carriere bank->bank_id + 'A', pin); 490430c415aSEtienne Carriere panic(); 491430c415aSEtienne Carriere } 492430c415aSEtienne Carriere } 493430c415aSEtienne Carriere 494430c415aSEtienne Carriere clk_disable(bank->clock); 495430c415aSEtienne Carriere } 496430c415aSEtienne Carriere #else 4974675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank __unused, 4984675225eSEtienne Carriere unsigned int pin __unused) 4994675225eSEtienne Carriere { 5004675225eSEtienne Carriere return true; 5014675225eSEtienne Carriere } 5024675225eSEtienne Carriere 503430c415aSEtienne Carriere static TEE_Result 504430c415aSEtienne Carriere acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank __unused, 505430c415aSEtienne Carriere unsigned int pin __unused) 506430c415aSEtienne Carriere { 507430c415aSEtienne Carriere return TEE_SUCCESS; 508430c415aSEtienne Carriere } 509430c415aSEtienne Carriere 510430c415aSEtienne Carriere static void 511430c415aSEtienne Carriere release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank __unused, 512430c415aSEtienne Carriere unsigned int pin __unused) 513430c415aSEtienne Carriere { 514430c415aSEtienne Carriere } 515430c415aSEtienne Carriere #endif /*CFG_STM32_RIF*/ 516430c415aSEtienne Carriere 5174675225eSEtienne Carriere static bool pin_is_secure(struct stm32_gpio_bank *bank, unsigned int pin) 5184675225eSEtienne Carriere { 5194675225eSEtienne Carriere bool secure = false; 5204675225eSEtienne Carriere 5214675225eSEtienne Carriere if (bank->rif_cfg || bank->sec_support) { 5224675225eSEtienne Carriere if (clk_enable(bank->clock)) 5234675225eSEtienne Carriere panic(); 5244675225eSEtienne Carriere 5254675225eSEtienne Carriere secure = io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(pin); 5264675225eSEtienne Carriere 5274675225eSEtienne Carriere clk_disable(bank->clock); 5284675225eSEtienne Carriere } 5294675225eSEtienne Carriere 5304675225eSEtienne Carriere return secure; 5314675225eSEtienne Carriere } 5324675225eSEtienne Carriere 533077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 534bfc43b68SGatien Chevallier static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 535077d486eSEtienne Carriere { 536077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 537077d486eSEtienne Carriere 538077d486eSEtienne Carriere if (clk_enable(bank->clock)) 539077d486eSEtienne Carriere panic(); 5404b5e93edSEtienne Carriere 5414b5e93edSEtienne Carriere /* 5424b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 5434b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 5444b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 5454b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 5464b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 5474b5e93edSEtienne Carriere */ 548077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 5494b5e93edSEtienne Carriere GPIO_MODE_MASK; 5504b5e93edSEtienne Carriere 551077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 5524b5e93edSEtienne Carriere 553077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 554077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 5554b5e93edSEtienne Carriere 556077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 5574b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 5584b5e93edSEtienne Carriere 559077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 5604b5e93edSEtienne Carriere 5614b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 562077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 563077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 5644b5e93edSEtienne Carriere else 565077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 5664b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 5674b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 5684b5e93edSEtienne Carriere 569077d486eSEtienne Carriere clk_disable(bank->clock); 5704b5e93edSEtienne Carriere } 5714b5e93edSEtienne Carriere 5724b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 573077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 5744b5e93edSEtienne Carriere { 575077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 57698dfcedaSEtienne Carriere uint32_t exceptions = 0; 5774b5e93edSEtienne Carriere 578077d486eSEtienne Carriere if (clk_enable(bank->clock)) 579077d486eSEtienne Carriere panic(); 58098dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 5814b5e93edSEtienne Carriere 5824b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 583077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 584bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 585bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 5864b5e93edSEtienne Carriere 5874b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 588077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 589bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 5904b5e93edSEtienne Carriere 5914b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 592077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 593bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 594bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 5954b5e93edSEtienne Carriere 5964b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 597077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 598bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 5994b5e93edSEtienne Carriere 6004b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 6014b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 602077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 603bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 604bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 6054b5e93edSEtienne Carriere } else { 6064b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 6074b5e93edSEtienne Carriere 608077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 609bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 610bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 6114b5e93edSEtienne Carriere } 6124b5e93edSEtienne Carriere 6134b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 614077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 6154b5e93edSEtienne Carriere 616c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 61798dfcedaSEtienne Carriere clk_disable(bank->clock); 6184b5e93edSEtienne Carriere } 6194b5e93edSEtienne Carriere 6204b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 621b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node, 622*5f27da69SEtienne Carriere int consumer_node __maybe_unused, 6234b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 6244b5e93edSEtienne Carriere { 625*5f27da69SEtienne Carriere struct stm32_gpio_bank *bank_ref = NULL; 626b38386fbSEtienne Carriere const fdt32_t *cuint = NULL; 627b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL; 62810bcbd6cSEtienne Carriere int len = 0; 62910bcbd6cSEtienne Carriere uint32_t i = 0; 6304b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 6314b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 6324b5e93edSEtienne Carriere size_t found = 0; 633*5f27da69SEtienne Carriere bool do_panic = false; 6344b5e93edSEtienne Carriere 6354b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 6364b5e93edSEtienne Carriere if (!cuint) 6374b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 6384b5e93edSEtienne Carriere 6394b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 6404b5e93edSEtienne Carriere if (slewrate) 6414b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 6424b5e93edSEtienne Carriere 6434b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 6444b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 6454b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 6464b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 6474b5e93edSEtienne Carriere 6484b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 64910bcbd6cSEtienne Carriere uint32_t pincfg = 0; 65010bcbd6cSEtienne Carriere uint32_t bank = 0; 65110bcbd6cSEtienne Carriere uint32_t pin = 0; 65210bcbd6cSEtienne Carriere uint32_t mode = 0; 6534b5e93edSEtienne Carriere uint32_t alternate = 0; 654322cf9e3SEtienne Carriere uint32_t odata = 0; 6554b5e93edSEtienne Carriere bool opendrain = false; 656*5f27da69SEtienne Carriere bool pin_non_secure = true; 6574b5e93edSEtienne Carriere 6584b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 6594b5e93edSEtienne Carriere cuint++; 6604b5e93edSEtienne Carriere 6614b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 6624b5e93edSEtienne Carriere 6634b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 6644b5e93edSEtienne Carriere 6654b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 6664b5e93edSEtienne Carriere 667*5f27da69SEtienne Carriere pin_non_secure = pincfg & STM32_PIN_NSEC; 668*5f27da69SEtienne Carriere 6694b5e93edSEtienne Carriere switch (mode) { 6704b5e93edSEtienne Carriere case 0: 6714b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 6724b5e93edSEtienne Carriere break; 6734b5e93edSEtienne Carriere case 1: 6744b5e93edSEtienne Carriere case 2: 6754b5e93edSEtienne Carriere case 3: 6764b5e93edSEtienne Carriere case 4: 6774b5e93edSEtienne Carriere case 5: 6784b5e93edSEtienne Carriere case 6: 6794b5e93edSEtienne Carriere case 7: 6804b5e93edSEtienne Carriere case 8: 6814b5e93edSEtienne Carriere case 9: 6824b5e93edSEtienne Carriere case 10: 6834b5e93edSEtienne Carriere case 11: 6844b5e93edSEtienne Carriere case 12: 6854b5e93edSEtienne Carriere case 13: 6864b5e93edSEtienne Carriere case 14: 6874b5e93edSEtienne Carriere case 15: 6884b5e93edSEtienne Carriere case 16: 6894b5e93edSEtienne Carriere alternate = mode - 1U; 6904b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 6914b5e93edSEtienne Carriere break; 6924b5e93edSEtienne Carriere case 17: 6934b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 6944b5e93edSEtienne Carriere break; 6954b5e93edSEtienne Carriere default: 6964b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 6974b5e93edSEtienne Carriere break; 6984b5e93edSEtienne Carriere } 6994b5e93edSEtienne Carriere 7004b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 7014b5e93edSEtienne Carriere opendrain = true; 7024b5e93edSEtienne Carriere 703322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 704322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 705322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 706322cf9e3SEtienne Carriere odata = 1; 707322cf9e3SEtienne Carriere } 708322cf9e3SEtienne Carriere 709322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 710322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 711322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 712322cf9e3SEtienne Carriere odata = 0; 713322cf9e3SEtienne Carriere } 714322cf9e3SEtienne Carriere 7154b5e93edSEtienne Carriere if (found < count) { 7164b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 7174b5e93edSEtienne Carriere 7184b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 7194b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 720b38386fbSEtienne Carriere ref->cfg.mode = mode; 721b38386fbSEtienne Carriere if (opendrain) 722b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN; 723b38386fbSEtienne Carriere else 724b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL; 725b38386fbSEtienne Carriere ref->cfg.ospeed = speed; 726b38386fbSEtienne Carriere ref->cfg.pupd = pull; 727b38386fbSEtienne Carriere ref->cfg.od = odata; 728b38386fbSEtienne Carriere ref->cfg.af = alternate; 729*5f27da69SEtienne Carriere ref->cfg.nsec = pin_non_secure; 730*5f27da69SEtienne Carriere 731*5f27da69SEtienne Carriere bank_ref = stm32_gpio_get_bank(bank); 732*5f27da69SEtienne Carriere 733*5f27da69SEtienne Carriere if (pin >= bank_ref->ngpios) { 734*5f27da69SEtienne Carriere EMSG("node %s requests pin %c%u that does not exist", 735*5f27da69SEtienne Carriere fdt_get_name(fdt, consumer_node, NULL), 736*5f27da69SEtienne Carriere bank + 'A', pin); 737*5f27da69SEtienne Carriere do_panic = true; 738*5f27da69SEtienne Carriere } 7394b5e93edSEtienne Carriere } 7404b5e93edSEtienne Carriere 7414b5e93edSEtienne Carriere found++; 7424b5e93edSEtienne Carriere } 7434b5e93edSEtienne Carriere 744*5f27da69SEtienne Carriere if (do_panic) 745*5f27da69SEtienne Carriere panic(); 746*5f27da69SEtienne Carriere 7474b5e93edSEtienne Carriere return (int)found; 7484b5e93edSEtienne Carriere } 7494b5e93edSEtienne Carriere 750bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, 751bfc43b68SGatien Chevallier unsigned int pm_hint __unused, 752bfc43b68SGatien Chevallier const struct pm_callback_handle *pm_hdl) 753bfc43b68SGatien Chevallier { 754bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *handle = pm_hdl->handle; 755bfc43b68SGatien Chevallier unsigned int bank_id = handle->gpio_pinctrl.bank; 756bfc43b68SGatien Chevallier unsigned int pin = handle->gpio_pinctrl.pin; 757bfc43b68SGatien Chevallier struct gpio_chip *chip = &stm32_gpio_get_bank(bank_id)->gpio_chip; 758bfc43b68SGatien Chevallier 759bfc43b68SGatien Chevallier if (op == PM_OP_RESUME) { 760bfc43b68SGatien Chevallier set_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg); 761bfc43b68SGatien Chevallier if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT) 762bfc43b68SGatien Chevallier stm32_gpio_set_level(chip, pin, handle->level); 763bfc43b68SGatien Chevallier } else { 764bfc43b68SGatien Chevallier get_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg); 765bfc43b68SGatien Chevallier if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT) 766bfc43b68SGatien Chevallier handle->level = stm32_gpio_get_level(chip, pin); 767bfc43b68SGatien Chevallier } 768bfc43b68SGatien Chevallier 769bfc43b68SGatien Chevallier return TEE_SUCCESS; 770bfc43b68SGatien Chevallier } 771bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(consumed_gpios_pm); 772bfc43b68SGatien Chevallier 773b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data, 774b357d34fSEtienne Carriere struct gpio **out_gpio) 775420a32c5SEtienne Carriere { 776b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 777430c415aSEtienne Carriere const char *consumer_name __maybe_unused = NULL; 7787761b658SEtienne Carriere struct stm32_gpio_pm_state *reg_state = NULL; 779bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *state = NULL; 780420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 781420a32c5SEtienne Carriere struct gpio *gpio = NULL; 782420a32c5SEtienne Carriere unsigned int shift_1b = 0; 783420a32c5SEtienne Carriere unsigned int shift_2b = 0; 7844675225eSEtienne Carriere bool gpio_secure = true; 785420a32c5SEtienne Carriere uint32_t exceptions = 0; 786420a32c5SEtienne Carriere uint32_t otype = 0; 787420a32c5SEtienne Carriere uint32_t pupd = 0; 788420a32c5SEtienne Carriere uint32_t mode = 0; 789420a32c5SEtienne Carriere 790430c415aSEtienne Carriere consumer_name = fdt_get_name(pargs->fdt, pargs->consumer_node, 791430c415aSEtienne Carriere NULL); 792430c415aSEtienne Carriere 793b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio); 794b357d34fSEtienne Carriere if (res) 795b357d34fSEtienne Carriere return res; 796420a32c5SEtienne Carriere 797420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 798420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 799420a32c5SEtienne Carriere free(gpio); 800b357d34fSEtienne Carriere return TEE_ERROR_GENERIC; 801420a32c5SEtienne Carriere } 802420a32c5SEtienne Carriere 8034675225eSEtienne Carriere if (gpio->dt_flags & GPIO_STM32_NSEC) 8044675225eSEtienne Carriere gpio_secure = false; 8054675225eSEtienne Carriere 806bfc43b68SGatien Chevallier state = calloc(1, sizeof(*state)); 807bfc43b68SGatien Chevallier if (!state) { 808bfc43b68SGatien Chevallier free(gpio); 809bfc43b68SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY; 810bfc43b68SGatien Chevallier } 811bfc43b68SGatien Chevallier 8127761b658SEtienne Carriere SLIST_FOREACH(reg_state, &consumed_gpios_head, link) { 8137761b658SEtienne Carriere if (reg_state->gpio_pinctrl.bank == bank->bank_id && 8147761b658SEtienne Carriere reg_state->gpio_pinctrl.pin == gpio->pin) { 8157761b658SEtienne Carriere EMSG("node %s: GPIO %c%u is used by another device", 8164675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin); 8177761b658SEtienne Carriere free(state); 8187761b658SEtienne Carriere free(gpio); 8197761b658SEtienne Carriere return TEE_ERROR_GENERIC; 8207761b658SEtienne Carriere } 8217761b658SEtienne Carriere } 8227761b658SEtienne Carriere 8234675225eSEtienne Carriere if (!pin_is_accessible(bank, gpio->pin)) { 8244675225eSEtienne Carriere EMSG("node %s requests pin on GPIO %c%u which access is denied", 8254675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin); 8264675225eSEtienne Carriere panic(); 8274675225eSEtienne Carriere } 8284675225eSEtienne Carriere 829430c415aSEtienne Carriere res = acquire_rif_semaphore_if_needed(bank, gpio->pin); 830430c415aSEtienne Carriere if (res) { 831430c415aSEtienne Carriere EMSG("Failed to acquire GPIO %c%u semaphore for node %s", 832430c415aSEtienne Carriere bank->bank_id + 'A', gpio->pin, consumer_name); 833430c415aSEtienne Carriere return res; 834430c415aSEtienne Carriere } 835430c415aSEtienne Carriere 8364675225eSEtienne Carriere if (gpio_secure && !(bank->rif_cfg || bank->sec_support)) { 8374675225eSEtienne Carriere EMSG("node %s requests secure GPIO %c%u that cannot be secured", 8384675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin); 8394675225eSEtienne Carriere panic(); 8404675225eSEtienne Carriere } 8414675225eSEtienne Carriere 8424675225eSEtienne Carriere if (gpio_secure != pin_is_secure(bank, gpio->pin)) { 8434675225eSEtienne Carriere IMSG("WARNING: node %s requests %s GPIO %c%u but pin is %s. Check st,protreg in GPIO bank node %s", 8444675225eSEtienne Carriere consumer_name, gpio_secure ? "secure" : "non-secure", 8454675225eSEtienne Carriere bank->bank_id + 'A', gpio->pin, 8464675225eSEtienne Carriere pin_is_secure(bank, gpio->pin) ? "secure" : "non-secure", 8474675225eSEtienne Carriere fdt_get_name(pargs->fdt, pargs->phandle_node, NULL)); 8484675225eSEtienne Carriere if (!IS_ENABLED(CFG_INSECURE)) 8494675225eSEtienne Carriere panic(); 8504675225eSEtienne Carriere } 8514675225eSEtienne Carriere 852bfc43b68SGatien Chevallier state->gpio_pinctrl.pin = gpio->pin; 853bfc43b68SGatien Chevallier state->gpio_pinctrl.bank = bank->bank_id; 854bfc43b68SGatien Chevallier SLIST_INSERT_HEAD(&consumed_gpios_head, state, link); 855bfc43b68SGatien Chevallier 856bfc43b68SGatien Chevallier register_pm_driver_cb(consumed_gpios_pm, state, "stm32-gpio-state"); 857bfc43b68SGatien Chevallier 858420a32c5SEtienne Carriere shift_1b = gpio->pin; 859420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 860420a32c5SEtienne Carriere 861420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 862420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 863420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 864420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 865420a32c5SEtienne Carriere else 866420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 867420a32c5SEtienne Carriere 868420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 869420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 870420a32c5SEtienne Carriere else 871420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 872420a32c5SEtienne Carriere 873420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 874420a32c5SEtienne Carriere panic(); 875420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 876420a32c5SEtienne Carriere 877420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 878420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 879420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 880420a32c5SEtienne Carriere 881420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 882420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 883420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 884420a32c5SEtienne Carriere 885420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 886420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 887420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 888420a32c5SEtienne Carriere 889420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 890420a32c5SEtienne Carriere clk_disable(bank->clock); 891420a32c5SEtienne Carriere 892420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 893420a32c5SEtienne Carriere 894b357d34fSEtienne Carriere *out_gpio = gpio; 895420a32c5SEtienne Carriere 896b357d34fSEtienne Carriere return TEE_SUCCESS; 897420a32c5SEtienne Carriere } 898420a32c5SEtienne Carriere 8999818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 9009818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 9019818a481SEtienne Carriere { 9029818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 9039818a481SEtienne Carriere const fdt32_t *cuint = NULL; 9049818a481SEtienne Carriere int len = 0; 9059818a481SEtienne Carriere 9069818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 9079818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 9089818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 9099818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 9109818a481SEtienne Carriere 9119818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 9129818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 9139818a481SEtienne Carriere panic("Wrong st,bank-name property"); 9149818a481SEtienne Carriere 9159818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 9169818a481SEtienne Carriere } 9179818a481SEtienne Carriere 9189818a481SEtienne Carriere /* 9199818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 9209818a481SEtienne Carriere * registered in the GPIO bank link. 9219818a481SEtienne Carriere */ 9229818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 9239818a481SEtienne Carriere { 9249818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 9259818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 9269818a481SEtienne Carriere 9279818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 9289818a481SEtienne Carriere if (bank->bank_id == bank_id) 9299818a481SEtienne Carriere return true; 9309818a481SEtienne Carriere 9319818a481SEtienne Carriere return false; 9329818a481SEtienne Carriere } 9339818a481SEtienne Carriere 9349def1fb7SGatien Chevallier #ifdef CFG_STM32_RIF 935a72f07daSEtienne Carriere static TEE_Result handle_available_semaphores(struct stm32_gpio_bank *bank, 936a72f07daSEtienne Carriere uint32_t gpios_mask) 937bd03c8c3SGatien Chevallier { 938bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 939bd03c8c3SGatien Chevallier uint32_t cidcfgr = 0; 940bd03c8c3SGatien Chevallier unsigned int i = 0; 941bd03c8c3SGatien Chevallier 9429def1fb7SGatien Chevallier for (i = 0 ; i < bank->ngpios; i++) { 943a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask)) 9449def1fb7SGatien Chevallier continue; 9459def1fb7SGatien Chevallier 9469def1fb7SGatien Chevallier cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i)); 9479def1fb7SGatien Chevallier 9489def1fb7SGatien Chevallier if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) 9499def1fb7SGatien Chevallier continue; 9509def1fb7SGatien Chevallier 9519def1fb7SGatien Chevallier if (!(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) { 9529def1fb7SGatien Chevallier res = stm32_rif_release_semaphore(bank->base + 9539def1fb7SGatien Chevallier GPIO_SEMCR(i), 9549def1fb7SGatien Chevallier MAX_CID_SUPPORTED); 9559def1fb7SGatien Chevallier if (res) { 9569def1fb7SGatien Chevallier EMSG("Cannot release semaphore for resource %u", 9579def1fb7SGatien Chevallier i); 9589def1fb7SGatien Chevallier return res; 9599def1fb7SGatien Chevallier } 9609def1fb7SGatien Chevallier } else { 9619def1fb7SGatien Chevallier res = stm32_rif_acquire_semaphore(bank->base + 9629def1fb7SGatien Chevallier GPIO_SEMCR(i), 9639def1fb7SGatien Chevallier MAX_CID_SUPPORTED); 9649def1fb7SGatien Chevallier if (res) { 9659def1fb7SGatien Chevallier EMSG("Cannot acquire semaphore for resource %u", 9669def1fb7SGatien Chevallier i); 9679def1fb7SGatien Chevallier return res; 9689def1fb7SGatien Chevallier } 9699def1fb7SGatien Chevallier } 9709def1fb7SGatien Chevallier } 9719def1fb7SGatien Chevallier 9729def1fb7SGatien Chevallier return TEE_SUCCESS; 9739def1fb7SGatien Chevallier } 9749def1fb7SGatien Chevallier 975a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank, 976a72f07daSEtienne Carriere uint32_t gpios_mask) 9779def1fb7SGatien Chevallier { 9789def1fb7SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 9799def1fb7SGatien Chevallier unsigned int i = 0; 9809def1fb7SGatien Chevallier 981bd03c8c3SGatien Chevallier if (!bank->rif_cfg) 982bd03c8c3SGatien Chevallier return TEE_SUCCESS; 983bd03c8c3SGatien Chevallier 984bd03c8c3SGatien Chevallier if (clk_enable(bank->clock)) 985bd03c8c3SGatien Chevallier panic(); 986bd03c8c3SGatien Chevallier 9879def1fb7SGatien Chevallier if (bank->is_tdcid) { 988bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) { 989a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask)) 990bd03c8c3SGatien Chevallier continue; 991bd03c8c3SGatien Chevallier 992bd03c8c3SGatien Chevallier /* 9939def1fb7SGatien Chevallier * When TDCID, OP-TEE should be the one to set the CID 9949def1fb7SGatien Chevallier * filtering configuration. Clearing previous 9959def1fb7SGatien Chevallier * configuration prevents undesired events during the 9969def1fb7SGatien Chevallier * only legitimate configuration. 997bd03c8c3SGatien Chevallier */ 998bd03c8c3SGatien Chevallier io_clrbits32(bank->base + GPIO_CIDCFGR(i), 999bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK); 1000bd03c8c3SGatien Chevallier } 10019def1fb7SGatien Chevallier } else { 1002a72f07daSEtienne Carriere res = handle_available_semaphores(bank, gpios_mask); 10039def1fb7SGatien Chevallier if (res) 10049def1fb7SGatien Chevallier panic(); 1005bd03c8c3SGatien Chevallier } 1006bd03c8c3SGatien Chevallier 1007bd03c8c3SGatien Chevallier /* Security and privilege RIF configuration */ 1008a72f07daSEtienne Carriere io_mask32(bank->base + GPIO_PRIVCFGR_OFFSET, 1009a72f07daSEtienne Carriere bank->rif_cfg->priv_conf[0], gpios_mask); 1010a72f07daSEtienne Carriere io_mask32(bank->base + GPIO_SECR_OFFSET, 1011a72f07daSEtienne Carriere bank->rif_cfg->sec_conf[0], gpios_mask); 1012bd03c8c3SGatien Chevallier 1013bd03c8c3SGatien Chevallier if (!bank->is_tdcid) { 1014bd03c8c3SGatien Chevallier res = TEE_SUCCESS; 1015bd03c8c3SGatien Chevallier goto out; 1016bd03c8c3SGatien Chevallier } 1017bd03c8c3SGatien Chevallier 1018bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) { 1019a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask)) 1020bd03c8c3SGatien Chevallier continue; 1021bd03c8c3SGatien Chevallier 1022bd03c8c3SGatien Chevallier io_clrsetbits32(bank->base + GPIO_CIDCFGR(i), 1023bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK, 1024bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs[i]); 1025bd03c8c3SGatien Chevallier } 1026bd03c8c3SGatien Chevallier 1027bd03c8c3SGatien Chevallier /* 1028bd03c8c3SGatien Chevallier * Lock RIF configuration if configured. This cannot be undone until 1029bd03c8c3SGatien Chevallier * next reset. 1030bd03c8c3SGatien Chevallier */ 1031bd03c8c3SGatien Chevallier io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET, 1032bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf[0]); 1033bd03c8c3SGatien Chevallier 1034a72f07daSEtienne Carriere res = handle_available_semaphores(bank, gpios_mask); 10359def1fb7SGatien Chevallier if (res) 10369def1fb7SGatien Chevallier panic(); 10379def1fb7SGatien Chevallier 10389def1fb7SGatien Chevallier out: 1039bd03c8c3SGatien Chevallier if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) { 1040bd03c8c3SGatien Chevallier /* Check that RIF config are applied, panic otherwise */ 1041bd03c8c3SGatien Chevallier if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) & 1042a72f07daSEtienne Carriere gpios_mask) != 1043a72f07daSEtienne Carriere (bank->rif_cfg->priv_conf[0] & gpios_mask)) { 1044bd03c8c3SGatien Chevallier EMSG("GPIO bank%c priv conf is incorrect", 1045bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 1046bd03c8c3SGatien Chevallier panic(); 1047bd03c8c3SGatien Chevallier } 1048bd03c8c3SGatien Chevallier 1049a72f07daSEtienne Carriere if ((io_read32(bank->base + GPIO_SECR_OFFSET) & gpios_mask) != 1050a72f07daSEtienne Carriere (bank->rif_cfg->sec_conf[0] & gpios_mask)) { 1051bd03c8c3SGatien Chevallier EMSG("GPIO bank %c sec conf is incorrect", 1052bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 1053bd03c8c3SGatien Chevallier panic(); 1054bd03c8c3SGatien Chevallier } 1055bd03c8c3SGatien Chevallier } 1056bd03c8c3SGatien Chevallier 1057bd03c8c3SGatien Chevallier clk_disable(bank->clock); 1058bd03c8c3SGatien Chevallier 1059bd03c8c3SGatien Chevallier return res; 1060bd03c8c3SGatien Chevallier } 10619def1fb7SGatien Chevallier #else /* CFG_STM32_RIF */ 1062a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank __unused, 1063a72f07daSEtienne Carriere uint32_t gpios_mask __unused) 10649def1fb7SGatien Chevallier { 10659def1fb7SGatien Chevallier return TEE_SUCCESS; 10669def1fb7SGatien Chevallier } 10679def1fb7SGatien Chevallier #endif /* CFG_STM32_RIF */ 1068bd03c8c3SGatien Chevallier 1069a650c9cbSEtienne Carriere /* Forward reference to stm32_gpio_set_conf_sec() defined below */ 1070a650c9cbSEtienne Carriere static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank); 1071a650c9cbSEtienne Carriere 1072a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_fw_configure(struct firewall_query *firewall) 1073a650c9cbSEtienne Carriere { 1074a650c9cbSEtienne Carriere struct stm32_gpio_bank *bank = firewall->ctrl->priv; 1075a650c9cbSEtienne Carriere uint32_t firewall_arg = 0; 1076a650c9cbSEtienne Carriere uint32_t gpios_mask = 0; 1077a650c9cbSEtienne Carriere bool secure = true; 1078a650c9cbSEtienne Carriere 1079a650c9cbSEtienne Carriere assert(bank->sec_support); 1080a650c9cbSEtienne Carriere 1081a650c9cbSEtienne Carriere if (firewall->arg_count != 1) 1082a650c9cbSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 1083a650c9cbSEtienne Carriere 1084a650c9cbSEtienne Carriere firewall_arg = firewall->args[0]; 1085a650c9cbSEtienne Carriere 1086a650c9cbSEtienne Carriere if (bank->rif_cfg) { 1087a650c9cbSEtienne Carriere gpios_mask = BIT(RIF_CHANNEL_ID(firewall_arg)); 1088a650c9cbSEtienne Carriere 1089a650c9cbSEtienne Carriere /* We're about to change a specific GPIO config */ 1090a650c9cbSEtienne Carriere bank->rif_cfg->access_mask[0] |= gpios_mask; 1091a650c9cbSEtienne Carriere 1092a650c9cbSEtienne Carriere /* 1093a650c9cbSEtienne Carriere * Update bank RIF config with firewall configuration data 1094a650c9cbSEtienne Carriere * and apply it. 1095a650c9cbSEtienne Carriere */ 1096a650c9cbSEtienne Carriere stm32_rif_parse_cfg(firewall_arg, bank->rif_cfg, 1097a650c9cbSEtienne Carriere bank->ngpios); 1098a650c9cbSEtienne Carriere return apply_rif_config(bank, gpios_mask); 1099a650c9cbSEtienne Carriere } 1100a650c9cbSEtienne Carriere 1101a650c9cbSEtienne Carriere /* 1102a650c9cbSEtienne Carriere * Non RIF GPIO banks use a single cell as a bit mask (bits 0 to 15) 1103a650c9cbSEtienne Carriere * to define the a group of GPIO pins (one or several) to configure 1104a650c9cbSEtienne Carriere * for that bank, and GPIO_STM32_NSEC bit flag to set if these pins 1105a650c9cbSEtienne Carriere * are non-secure (flag set) or non-secure (flag cleared). 1106a650c9cbSEtienne Carriere */ 1107a650c9cbSEtienne Carriere gpios_mask = firewall_arg & GENMASK_32(15, 0); 1108a650c9cbSEtienne Carriere 1109a650c9cbSEtienne Carriere secure = !(firewall_arg & GPIO_STM32_NSEC); 1110a650c9cbSEtienne Carriere 1111a650c9cbSEtienne Carriere if (gpios_mask & ~GENMASK_32(bank->ngpios, 0)) { 1112a650c9cbSEtienne Carriere EMSG("Invalid bitmask %#"PRIx32" for GPIO bank %c", 1113a650c9cbSEtienne Carriere gpios_mask, 'A' + bank->bank_id); 1114a650c9cbSEtienne Carriere return TEE_ERROR_GENERIC; 1115a650c9cbSEtienne Carriere } 1116a650c9cbSEtienne Carriere 1117a650c9cbSEtienne Carriere /* Update bank secure register configuration data and apply it */ 1118a650c9cbSEtienne Carriere if (secure) 1119a650c9cbSEtienne Carriere bank->seccfgr |= gpios_mask; 1120a650c9cbSEtienne Carriere else 1121a650c9cbSEtienne Carriere bank->seccfgr &= ~gpios_mask; 1122a650c9cbSEtienne Carriere 1123a650c9cbSEtienne Carriere stm32_gpio_set_conf_sec(bank); 1124a650c9cbSEtienne Carriere 1125a650c9cbSEtienne Carriere return TEE_SUCCESS; 1126a650c9cbSEtienne Carriere } 1127a650c9cbSEtienne Carriere 1128a650c9cbSEtienne Carriere static const struct firewall_controller_ops stm32_gpio_firewall_ops = { 1129a650c9cbSEtienne Carriere .set_conf = stm32_gpio_fw_configure, 1130a650c9cbSEtienne Carriere }; 1131a650c9cbSEtienne Carriere 1132bfc43b68SGatien Chevallier static void stm32_gpio_save_rif_config(struct stm32_gpio_bank *bank) 1133bfc43b68SGatien Chevallier { 1134bfc43b68SGatien Chevallier size_t i = 0; 1135bfc43b68SGatien Chevallier 1136bfc43b68SGatien Chevallier for (i = 0; i < bank->ngpios; i++) 1137bfc43b68SGatien Chevallier bank->rif_cfg->cid_confs[i] = io_read32(bank->base + 1138bfc43b68SGatien Chevallier GPIO_CIDCFGR(i)); 1139bfc43b68SGatien Chevallier 1140bfc43b68SGatien Chevallier bank->rif_cfg->priv_conf[0] = io_read32(bank->base + 1141bfc43b68SGatien Chevallier GPIO_PRIVCFGR_OFFSET); 1142bfc43b68SGatien Chevallier bank->rif_cfg->sec_conf[0] = io_read32(bank->base + 1143bfc43b68SGatien Chevallier GPIO_SECR_OFFSET); 1144bfc43b68SGatien Chevallier bank->rif_cfg->lock_conf[0] = io_read32(bank->base + 1145bfc43b68SGatien Chevallier GPIO_RCFGLOCKR_OFFSET); 1146bfc43b68SGatien Chevallier } 1147bfc43b68SGatien Chevallier 1148bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank, 1149bd03c8c3SGatien Chevallier const void *fdt, int node) 1150bd03c8c3SGatien Chevallier { 1151bd03c8c3SGatien Chevallier unsigned int i = 0; 1152bd03c8c3SGatien Chevallier unsigned int nb_rif_conf = 0; 1153bd03c8c3SGatien Chevallier int lenp = 0; 1154bd03c8c3SGatien Chevallier const fdt32_t *cuint = NULL; 1155bd03c8c3SGatien Chevallier 1156bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); 1157bd03c8c3SGatien Chevallier if (!cuint) { 1158bd03c8c3SGatien Chevallier DMSG("No RIF configuration available"); 1159bd03c8c3SGatien Chevallier return; 1160bd03c8c3SGatien Chevallier } 1161bd03c8c3SGatien Chevallier 1162bd03c8c3SGatien Chevallier bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg)); 1163bd03c8c3SGatien Chevallier if (!bank->rif_cfg) 1164bd03c8c3SGatien Chevallier panic(); 1165bd03c8c3SGatien Chevallier 1166bd03c8c3SGatien Chevallier bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t)); 1167bd03c8c3SGatien Chevallier if (!bank->rif_cfg->sec_conf) 1168bd03c8c3SGatien Chevallier panic(); 1169bd03c8c3SGatien Chevallier 1170bd03c8c3SGatien Chevallier nb_rif_conf = (unsigned int)(lenp / sizeof(uint32_t)); 1171bd03c8c3SGatien Chevallier assert(nb_rif_conf <= bank->ngpios); 1172bd03c8c3SGatien Chevallier 1173bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t)); 1174bd03c8c3SGatien Chevallier bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t)); 1175bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t)); 1176bd03c8c3SGatien Chevallier bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t)); 1177bd03c8c3SGatien Chevallier if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask || 1178bd03c8c3SGatien Chevallier !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf) 1179bd03c8c3SGatien Chevallier panic("Missing memory capacity for GPIOS RIF configuration"); 1180bd03c8c3SGatien Chevallier 1181bd03c8c3SGatien Chevallier for (i = 0; i < nb_rif_conf; i++) 1182bd03c8c3SGatien Chevallier stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg, 1183646ad62bSGatien Chevallier bank->ngpios); 1184bd03c8c3SGatien Chevallier } 1185bd03c8c3SGatien Chevallier 11869818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 11879818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 1188e569f6adSEtienne Carriere const void *compat_data, 11899818a481SEtienne Carriere int range_offset, 11909818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 11919818a481SEtienne Carriere { 1192e569f6adSEtienne Carriere const struct bank_compat *compat = compat_data; 11939818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 11949818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 11959818a481SEtienne Carriere const fdt32_t *cuint = NULL; 11969818a481SEtienne Carriere struct io_pa_va pa_va = { }; 11979818a481SEtienne Carriere struct clk *clk = NULL; 11989818a481SEtienne Carriere size_t blen = 0; 11999818a481SEtienne Carriere paddr_t pa = 0; 12009818a481SEtienne Carriere int len = 0; 12019818a481SEtienne Carriere int i = 0; 12029818a481SEtienne Carriere 12039818a481SEtienne Carriere assert(out_bank); 12049818a481SEtienne Carriere 12059818a481SEtienne Carriere /* Probe deferrable devices first */ 12069818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 12079818a481SEtienne Carriere if (res) 12089818a481SEtienne Carriere return res; 12099818a481SEtienne Carriere 12109818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 12119818a481SEtienne Carriere if (!bank) 12129818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 12139818a481SEtienne Carriere 1214bd03c8c3SGatien Chevallier if (compat->secure_extended) { 1215bd03c8c3SGatien Chevallier res = stm32_rifsc_check_tdcid(&bank->is_tdcid); 1216bd03c8c3SGatien Chevallier if (res) { 1217bd03c8c3SGatien Chevallier free(bank); 1218bd03c8c3SGatien Chevallier return res; 1219bd03c8c3SGatien Chevallier } 1220bd03c8c3SGatien Chevallier } 1221bd03c8c3SGatien Chevallier 12229818a481SEtienne Carriere /* 12239818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 12249818a481SEtienne Carriere * but consider also the "ranges" translation property 12259818a481SEtienne Carriere */ 12266a0116edSEtienne Carriere if (fdt_reg_info(fdt, node, &pa, &blen)) 12276a0116edSEtienne Carriere panic("missing reg or reg size property"); 12289818a481SEtienne Carriere 12299818a481SEtienne Carriere pa_va.pa = pa + range_offset; 12309818a481SEtienne Carriere 12319818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 12329818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 12339818a481SEtienne Carriere bank->clock = clk; 1234420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 1235b4893304SGatien Chevallier bank->sec_support = compat->secure_control; 12369818a481SEtienne Carriere 12379818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 12389818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 12399818a481SEtienne Carriere len /= sizeof(*cuint); 12409818a481SEtienne Carriere if (len % 4) 12419818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 12429818a481SEtienne Carriere 12439818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 12449818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 12459818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 12469818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 12479818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 12489818a481SEtienne Carriere cuint += 4; 12499818a481SEtienne Carriere } 12509818a481SEtienne Carriere 1251bd03c8c3SGatien Chevallier if (compat->secure_extended) { 1252bd03c8c3SGatien Chevallier /* RIF configuration */ 1253bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen); 1254bd03c8c3SGatien Chevallier 1255bd03c8c3SGatien Chevallier stm32_parse_gpio_rif_conf(bank, fdt, node); 1256bd03c8c3SGatien Chevallier } else if (bank->sec_support) { 1257bd03c8c3SGatien Chevallier /* Secure configuration */ 1258bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen); 1259bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", NULL); 1260bd03c8c3SGatien Chevallier if (cuint) 1261bd03c8c3SGatien Chevallier bank->seccfgr = fdt32_to_cpu(*cuint); 1262bd03c8c3SGatien Chevallier else 1263bd03c8c3SGatien Chevallier DMSG("GPIO bank %c assigned to non-secure", 1264bd03c8c3SGatien Chevallier bank->bank_id + 'A'); 1265bd03c8c3SGatien Chevallier } else { 1266bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_nsec(&pa_va, blen); 1267bd03c8c3SGatien Chevallier } 1268bd03c8c3SGatien Chevallier 1269e569f6adSEtienne Carriere if (compat->gpioz) 1270e569f6adSEtienne Carriere stm32mp_register_gpioz_pin_count(bank->ngpios); 1271e569f6adSEtienne Carriere 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 1370077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 1371077d486eSEtienne Carriere bool secure) 13724b5e93edSEtienne Carriere { 1373077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 137498dfcedaSEtienne Carriere uint32_t exceptions = 0; 13754b5e93edSEtienne Carriere 1376077d486eSEtienne Carriere if (clk_enable(bank->clock)) 1377077d486eSEtienne Carriere panic(); 137898dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 13794b5e93edSEtienne Carriere 13804b5e93edSEtienne Carriere if (secure) 1381077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 13824b5e93edSEtienne Carriere else 1383077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 13844b5e93edSEtienne Carriere 1385c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 138698dfcedaSEtienne Carriere clk_disable(bank->clock); 13874b5e93edSEtienne Carriere } 13880e0435e2SEtienne Carriere 1389b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 1390b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf) 1391b38386fbSEtienne Carriere { 1392b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv; 1393b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl; 1394430c415aSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 1395430c415aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 1396b38386fbSEtienne Carriere size_t pin_count = ref->count; 1397b38386fbSEtienne Carriere size_t n = 0; 1398430c415aSEtienne Carriere bool error = false; 1399430c415aSEtienne Carriere 1400430c415aSEtienne Carriere for (n = 0; n < pin_count; n++) { 1401430c415aSEtienne Carriere bank = stm32_gpio_get_bank(p[n].bank); 1402*5f27da69SEtienne Carriere 1403*5f27da69SEtienne Carriere if (!pin_is_accessible(bank, p[n].pin)) { 1404*5f27da69SEtienne Carriere EMSG("Apply pinctrl for pin %c%u that cannot be accessed", 1405*5f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin); 1406*5f27da69SEtienne Carriere error = true; 1407*5f27da69SEtienne Carriere continue; 1408*5f27da69SEtienne Carriere } 1409*5f27da69SEtienne Carriere 1410430c415aSEtienne Carriere res = acquire_rif_semaphore_if_needed(bank, p[n].pin); 1411430c415aSEtienne Carriere if (res) { 1412430c415aSEtienne Carriere EMSG("Failed to acquire GPIO %c%u semaphore", 1413430c415aSEtienne Carriere bank->bank_id + 'A', p[n].pin); 1414430c415aSEtienne Carriere error = true; 1415*5f27da69SEtienne Carriere continue; 1416*5f27da69SEtienne Carriere } 1417*5f27da69SEtienne Carriere 1418*5f27da69SEtienne Carriere if (p[n].cfg.nsec == !pin_is_secure(bank, p[n].pin)) 1419*5f27da69SEtienne Carriere continue; 1420*5f27da69SEtienne Carriere 1421*5f27da69SEtienne Carriere if (IS_ENABLED(CFG_INSECURE)) { 1422*5f27da69SEtienne Carriere IMSG("WARNING: apply pinctrl for %ssecure pin %c%u that is %ssecure", 1423*5f27da69SEtienne Carriere p[n].cfg.nsec ? "non-" : "", 1424*5f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin, 1425*5f27da69SEtienne Carriere pin_is_secure(bank, p[n].pin) ? "" : "non-"); 1426*5f27da69SEtienne Carriere } else { 1427*5f27da69SEtienne Carriere EMSG("Apply pinctrl for %ssecure pin %c%u that is %ssecure", 1428*5f27da69SEtienne Carriere p[n].cfg.nsec ? "non-" : "", 1429*5f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin, 1430*5f27da69SEtienne Carriere pin_is_secure(bank, p[n].pin) ? "" : "non-"); 1431*5f27da69SEtienne Carriere error = true; 1432430c415aSEtienne Carriere } 1433430c415aSEtienne Carriere } 1434430c415aSEtienne Carriere 1435430c415aSEtienne Carriere if (error) { 1436430c415aSEtienne Carriere for (n = 0; n < pin_count; n++) { 1437430c415aSEtienne Carriere bank = stm32_gpio_get_bank(p[n].bank); 1438430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, p[n].pin); 1439430c415aSEtienne Carriere } 1440430c415aSEtienne Carriere 1441430c415aSEtienne Carriere return TEE_ERROR_SECURITY; 1442430c415aSEtienne Carriere } 1443b38386fbSEtienne Carriere 1444b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++) 1445b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg); 1446b38386fbSEtienne Carriere 1447b38386fbSEtienne Carriere return TEE_SUCCESS; 1448b38386fbSEtienne Carriere } 1449b38386fbSEtienne Carriere 1450b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf) 1451b38386fbSEtienne Carriere { 1452b38386fbSEtienne Carriere free(conf); 1453b38386fbSEtienne Carriere } 1454b38386fbSEtienne Carriere 1455b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = { 1456b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply, 1457b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free, 1458b38386fbSEtienne Carriere }; 1459b38386fbSEtienne Carriere 1460b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops); 1461b38386fbSEtienne Carriere 146270ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl, 146370ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin, 146470ac0db5SEtienne Carriere unsigned int *count) 146570ac0db5SEtienne Carriere { 146670ac0db5SEtienne Carriere size_t conf_index = 0; 146770ac0db5SEtienne Carriere size_t pin_count = 0; 146870ac0db5SEtienne Carriere size_t n = 0; 146970ac0db5SEtienne Carriere 147070ac0db5SEtienne Carriere assert(count); 147170ac0db5SEtienne Carriere if (!pinctrl) 147270ac0db5SEtienne Carriere goto out; 147370ac0db5SEtienne Carriere 147470ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 147570ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 147670ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 147770ac0db5SEtienne Carriere 147870ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */ 147970ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 148070ac0db5SEtienne Carriere continue; 148170ac0db5SEtienne Carriere 148270ac0db5SEtienne Carriere if (bank || pin) { 148370ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) { 148470ac0db5SEtienne Carriere if (bank && pin_count < *count) 148570ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank; 148670ac0db5SEtienne Carriere if (pin && pin_count < *count) 148770ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin; 148870ac0db5SEtienne Carriere pin_count++; 148970ac0db5SEtienne Carriere } 149070ac0db5SEtienne Carriere } else { 149170ac0db5SEtienne Carriere pin_count += ref->count; 149270ac0db5SEtienne Carriere } 149370ac0db5SEtienne Carriere } 149470ac0db5SEtienne Carriere 149570ac0db5SEtienne Carriere out: 149670ac0db5SEtienne Carriere *count = pin_count; 149770ac0db5SEtienne Carriere } 149870ac0db5SEtienne Carriere 14997f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure) 15007f823a77SEtienne Carriere { 15017f823a77SEtienne Carriere size_t conf_index = 0; 15027f823a77SEtienne Carriere 15037f823a77SEtienne Carriere if (!pinctrl) 15047f823a77SEtienne Carriere return; 15057f823a77SEtienne Carriere 15067f823a77SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 15077f823a77SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 15087f823a77SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 15097f823a77SEtienne Carriere struct stm32_pinctrl *pc = NULL; 15107f823a77SEtienne Carriere size_t n = 0; 15117f823a77SEtienne Carriere 15127f823a77SEtienne Carriere for (n = 0; n < ref->count; n++) { 15137f823a77SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 15147f823a77SEtienne Carriere continue; 15157f823a77SEtienne Carriere 15167f823a77SEtienne Carriere pc = ref->pinctrl + n; 15177f823a77SEtienne Carriere stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure); 15187f823a77SEtienne Carriere } 15197f823a77SEtienne Carriere } 15207f823a77SEtienne Carriere } 15217f823a77SEtienne Carriere 1522b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */ 1523b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs, 1524b38386fbSEtienne Carriere void *data __unused, 1525b38386fbSEtienne Carriere struct pinconf **out_pinconf) 1526b38386fbSEtienne Carriere { 1527b38386fbSEtienne Carriere struct conf { 1528b38386fbSEtienne Carriere struct pinconf pinconf; 1529b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref; 1530b38386fbSEtienne Carriere } *loc_conf = NULL; 1531b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL; 1532b38386fbSEtienne Carriere struct pinconf *pinconf = NULL; 1533b38386fbSEtienne Carriere const void *fdt = NULL; 1534b38386fbSEtienne Carriere size_t pin_count = 0; 1535b38386fbSEtienne Carriere int pinctrl_node = 0; 1536b38386fbSEtienne Carriere int pinmux_node = 0; 1537b38386fbSEtienne Carriere int count = 0; 1538b38386fbSEtienne Carriere 1539b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node; 1540b38386fbSEtienne Carriere fdt = pargs->fdt; 1541b38386fbSEtienne Carriere assert(fdt && pinctrl_node); 1542b38386fbSEtienne Carriere 1543b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 1544b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count)) 1545b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t); 1546b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND) 1547b38386fbSEtienne Carriere panic(); 1548b38386fbSEtienne Carriere } 1549b38386fbSEtienne Carriere 1550b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count); 1551b38386fbSEtienne Carriere if (!loc_conf) 1552b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 1553b38386fbSEtienne Carriere 1554b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf; 1555b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops; 1556b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref; 1557b38386fbSEtienne Carriere 1558b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count; 1559b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl; 1560b38386fbSEtienne Carriere 1561b38386fbSEtienne Carriere count = 0; 1562b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 1563b38386fbSEtienne Carriere int found = 0; 1564b38386fbSEtienne Carriere 1565*5f27da69SEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node, 1566*5f27da69SEtienne Carriere pargs->consumer_node, 1567*5f27da69SEtienne Carriere pinctrl + count, 1568b38386fbSEtienne Carriere pin_count - count); 1569b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) { 1570b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */ 1571b38386fbSEtienne Carriere panic(); 1572b38386fbSEtienne Carriere } 1573b38386fbSEtienne Carriere 1574b38386fbSEtienne Carriere count += found; 1575b38386fbSEtienne Carriere } 1576b38386fbSEtienne Carriere 1577b38386fbSEtienne Carriere *out_pinconf = pinconf; 1578b38386fbSEtienne Carriere 1579b38386fbSEtienne Carriere return TEE_SUCCESS; 1580b38386fbSEtienne Carriere } 1581b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 1582b38386fbSEtienne Carriere 1583bfc43b68SGatien Chevallier static void stm32_gpio_get_conf_sec(struct stm32_gpio_bank *bank) 1584bfc43b68SGatien Chevallier { 1585bfc43b68SGatien Chevallier if (bank->sec_support) { 1586bfc43b68SGatien Chevallier clk_enable(bank->clock); 1587bfc43b68SGatien Chevallier bank->seccfgr = io_read32(bank->base + GPIO_SECR_OFFSET); 1588bfc43b68SGatien Chevallier clk_disable(bank->clock); 1589bfc43b68SGatien Chevallier } 1590bfc43b68SGatien Chevallier } 1591bfc43b68SGatien Chevallier 1592bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank) 1593bd03c8c3SGatien Chevallier { 1594bd03c8c3SGatien Chevallier if (bank->sec_support) { 1595bd03c8c3SGatien Chevallier clk_enable(bank->clock); 1596bd03c8c3SGatien Chevallier io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr); 1597bd03c8c3SGatien Chevallier clk_disable(bank->clock); 1598bd03c8c3SGatien Chevallier } 1599bd03c8c3SGatien Chevallier } 1600bd03c8c3SGatien Chevallier 1601bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_resume(void) 1602bfc43b68SGatien Chevallier { 1603bfc43b68SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 1604bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = NULL; 1605bfc43b68SGatien Chevallier 1606bfc43b68SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) { 1607bfc43b68SGatien Chevallier if (bank->rif_cfg) { 1608bfc43b68SGatien Chevallier if (!bank->is_tdcid) 1609bfc43b68SGatien Chevallier continue; 1610bfc43b68SGatien Chevallier 1611bfc43b68SGatien Chevallier bank->rif_cfg->access_mask[0] = GENMASK_32(bank->ngpios, 1612bfc43b68SGatien Chevallier 0); 1613bfc43b68SGatien Chevallier 1614a72f07daSEtienne Carriere res = apply_rif_config(bank, 1615a72f07daSEtienne Carriere bank->rif_cfg->access_mask[0]); 1616bfc43b68SGatien Chevallier if (res) { 1617bfc43b68SGatien Chevallier EMSG("Failed to set GPIO bank %c RIF config", 1618bfc43b68SGatien Chevallier 'A' + bank->bank_id); 1619bfc43b68SGatien Chevallier return res; 1620bfc43b68SGatien Chevallier } 1621bfc43b68SGatien Chevallier } else { 1622bfc43b68SGatien Chevallier stm32_gpio_set_conf_sec(bank); 1623bfc43b68SGatien Chevallier } 1624bfc43b68SGatien Chevallier } 1625bfc43b68SGatien Chevallier 1626bfc43b68SGatien Chevallier return TEE_SUCCESS; 1627bfc43b68SGatien Chevallier } 1628bfc43b68SGatien Chevallier 1629bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_suspend(void) 1630bfc43b68SGatien Chevallier { 1631bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = NULL; 1632bfc43b68SGatien Chevallier 1633bfc43b68SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) { 1634bfc43b68SGatien Chevallier if (bank->rif_cfg) { 1635bfc43b68SGatien Chevallier if (bank->is_tdcid) 1636bfc43b68SGatien Chevallier stm32_gpio_save_rif_config(bank); 1637bfc43b68SGatien Chevallier } else { 1638bfc43b68SGatien Chevallier stm32_gpio_get_conf_sec(bank); 1639bfc43b68SGatien Chevallier } 1640bfc43b68SGatien Chevallier } 1641bfc43b68SGatien Chevallier 1642bfc43b68SGatien Chevallier return TEE_SUCCESS; 1643bfc43b68SGatien Chevallier } 1644bfc43b68SGatien Chevallier 1645bfc43b68SGatien Chevallier static TEE_Result 1646bfc43b68SGatien Chevallier stm32_gpio_sec_config_pm(enum pm_op op, unsigned int pm_hint, 1647bfc43b68SGatien Chevallier const struct pm_callback_handle *hdl __unused) 1648bfc43b68SGatien Chevallier { 1649bfc43b68SGatien Chevallier TEE_Result ret = TEE_ERROR_GENERIC; 1650bfc43b68SGatien Chevallier 1651bfc43b68SGatien Chevallier if (!PM_HINT_IS_STATE(pm_hint, CONTEXT)) 1652bfc43b68SGatien Chevallier return TEE_SUCCESS; 1653bfc43b68SGatien Chevallier 1654bfc43b68SGatien Chevallier if (op == PM_OP_RESUME) 1655bfc43b68SGatien Chevallier ret = stm32_gpio_sec_config_resume(); 1656bfc43b68SGatien Chevallier else 1657bfc43b68SGatien Chevallier ret = stm32_gpio_sec_config_suspend(); 1658bfc43b68SGatien Chevallier 1659bfc43b68SGatien Chevallier return ret; 1660bfc43b68SGatien Chevallier } 1661bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(stm32_gpio_sec_config_pm); 1662bfc43b68SGatien Chevallier 1663bd03c8c3SGatien Chevallier /* 1664bd03c8c3SGatien Chevallier * Several pinctrl nodes can be probed. Their bank will be put in the unique 1665bd03c8c3SGatien Chevallier * bank_list. To avoid multiple configuration set for a bank when looping 1666bd03c8c3SGatien Chevallier * over each bank in the bank list, ready is set to true when a bank is 1667bd03c8c3SGatien Chevallier * configured. Therefore, during other bank probes, the configuration won't 1668bd03c8c3SGatien Chevallier * be set again. 1669bd03c8c3SGatien Chevallier */ 1670bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void) 1671bd03c8c3SGatien Chevallier { 1672bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 1673bd03c8c3SGatien Chevallier struct stm32_gpio_bank *bank = NULL; 1674430c415aSEtienne Carriere unsigned int pin = 0; 1675bd03c8c3SGatien Chevallier 1676bd03c8c3SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) { 1677bd03c8c3SGatien Chevallier if (bank->ready) 1678bd03c8c3SGatien Chevallier continue; 1679bd03c8c3SGatien Chevallier 1680bd03c8c3SGatien Chevallier if (bank->rif_cfg) { 1681a72f07daSEtienne Carriere res = apply_rif_config(bank, 1682a72f07daSEtienne Carriere bank->rif_cfg->access_mask[0]); 1683bd03c8c3SGatien Chevallier if (res) { 1684bd03c8c3SGatien Chevallier EMSG("Failed to set GPIO bank %c RIF config", 1685bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 1686bd03c8c3SGatien Chevallier STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank, 1687bd03c8c3SGatien Chevallier link); 16889def1fb7SGatien Chevallier free(bank); 1689bd03c8c3SGatien Chevallier return res; 1690bd03c8c3SGatien Chevallier } 1691430c415aSEtienne Carriere 1692430c415aSEtienne Carriere /* 1693430c415aSEtienne Carriere * Semaphores for pinctrl and GPIO are taken when 1694430c415aSEtienne Carriere * these are used (pinctrl state applied, GPIO 1695430c415aSEtienne Carriere * consumed) or when an explicit firewall configuration 1696430c415aSEtienne Carriere * is requested through the firewall framework. 1697430c415aSEtienne Carriere * Therefore release here the taken semaphores. 1698430c415aSEtienne Carriere */ 1699430c415aSEtienne Carriere for (pin = 0; pin < bank->ngpios; pin++) 1700430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, pin); 1701430c415aSEtienne Carriere 1702bd03c8c3SGatien Chevallier } else { 1703bd03c8c3SGatien Chevallier stm32_gpio_set_conf_sec(bank); 1704bd03c8c3SGatien Chevallier } 1705bd03c8c3SGatien Chevallier 1706bd03c8c3SGatien Chevallier bank->ready = true; 1707bd03c8c3SGatien Chevallier } 1708bd03c8c3SGatien Chevallier 1709bd03c8c3SGatien Chevallier return TEE_SUCCESS; 1710bd03c8c3SGatien Chevallier } 1711bd03c8c3SGatien Chevallier 17120e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 17130e0435e2SEtienne Carriere const void *compat_data) 17140e0435e2SEtienne Carriere { 1715bfc43b68SGatien Chevallier static bool pm_register; 1716b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 1717b38386fbSEtienne Carriere 17180e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 1719b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data); 1720b38386fbSEtienne Carriere if (res) 1721b38386fbSEtienne Carriere return res; 1722b38386fbSEtienne Carriere 1723bd03c8c3SGatien Chevallier if (STAILQ_EMPTY(&bank_list)) 1724bd03c8c3SGatien Chevallier DMSG("no gpio bank for that driver"); 1725bd03c8c3SGatien Chevallier else if (apply_sec_cfg()) 1726bd03c8c3SGatien Chevallier panic(); 1727bd03c8c3SGatien Chevallier 1728bfc43b68SGatien Chevallier if (!pm_register) { 1729bfc43b68SGatien Chevallier /* 1730bfc43b68SGatien Chevallier * Register to PM once for all probed banks to restore 1731bfc43b68SGatien Chevallier * their secure configuration. 1732bfc43b68SGatien Chevallier */ 1733bfc43b68SGatien Chevallier register_pm_driver_cb(stm32_gpio_sec_config_pm, NULL, 1734bfc43b68SGatien Chevallier "stm32-gpio-secure-config"); 1735bfc43b68SGatien Chevallier pm_register = true; 1736bfc43b68SGatien Chevallier } 1737bfc43b68SGatien Chevallier 1738b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 1739b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get, 1740b38386fbSEtienne Carriere (void *)compat_data); 1741b38386fbSEtienne Carriere if (res) 1742bd03c8c3SGatien Chevallier panic(); 1743b38386fbSEtienne Carriere #endif 1744b38386fbSEtienne Carriere 1745b38386fbSEtienne Carriere return TEE_SUCCESS; 17460e0435e2SEtienne Carriere } 17470e0435e2SEtienne Carriere 17480e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 1749e569f6adSEtienne Carriere { 1750e569f6adSEtienne Carriere .compatible = "st,stm32mp135-pinctrl", 1751b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1752b4893304SGatien Chevallier .secure_control = true, 1753bd03c8c3SGatien Chevallier .secure_extended = false, 1754b4893304SGatien Chevallier }, 1755e569f6adSEtienne Carriere }, 1756e569f6adSEtienne Carriere { 1757e569f6adSEtienne Carriere .compatible = "st,stm32mp157-pinctrl", 1758b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1759b4893304SGatien Chevallier .secure_control = false, 1760bd03c8c3SGatien Chevallier .secure_extended = false, 1761b4893304SGatien Chevallier }, 1762e569f6adSEtienne Carriere }, 1763e569f6adSEtienne Carriere { 1764e569f6adSEtienne Carriere .compatible = "st,stm32mp157-z-pinctrl", 1765b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1766b4893304SGatien Chevallier .gpioz = true, 1767b4893304SGatien Chevallier .secure_control = true, 1768bd03c8c3SGatien Chevallier .secure_extended = false, 1769bd03c8c3SGatien Chevallier }, 1770bd03c8c3SGatien Chevallier }, 1771bd03c8c3SGatien Chevallier { 1772bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-pinctrl", 1773bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){ 1774bd03c8c3SGatien Chevallier .secure_control = true, 1775bd03c8c3SGatien Chevallier .secure_extended = true, 1776bd03c8c3SGatien Chevallier }, 1777bd03c8c3SGatien Chevallier }, 1778bd03c8c3SGatien Chevallier { 1779bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-z-pinctrl", 1780bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){ 1781bd03c8c3SGatien Chevallier .gpioz = true, 1782bd03c8c3SGatien Chevallier .secure_control = true, 1783bd03c8c3SGatien Chevallier .secure_extended = true, 1784b4893304SGatien Chevallier }, 1785e569f6adSEtienne Carriere }, 17860e0435e2SEtienne Carriere { } 17870e0435e2SEtienne Carriere }; 17880e0435e2SEtienne Carriere 17890e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 17900e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 17910e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 17920e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 17930e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 17940e0435e2SEtienne Carriere }; 1795