14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 24b5e93edSEtienne Carriere /* 3*bd03c8c3SGatien 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> 12420a32c5SEtienne Carriere #include <drivers/gpio.h> 13b38386fbSEtienne Carriere #include <drivers/pinctrl.h> 144b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h> 15*bd03c8c3SGatien Chevallier #include <drivers/stm32_rif.h> 16*bd03c8c3SGatien Chevallier #include <dt-bindings/gpio/gpio.h> 174b5e93edSEtienne Carriere #include <io.h> 184b5e93edSEtienne Carriere #include <kernel/dt.h> 1965401337SJens Wiklander #include <kernel/boot.h> 204b5e93edSEtienne Carriere #include <kernel/panic.h> 214b5e93edSEtienne Carriere #include <kernel/spinlock.h> 22a2fc83d1SJerome Forissier #include <libfdt.h> 234b5e93edSEtienne Carriere #include <mm/core_memprot.h> 244b5e93edSEtienne Carriere #include <stdbool.h> 2569715ce9SEtienne Carriere #include <stdint.h> 264b5e93edSEtienne Carriere #include <stm32_util.h> 279818a481SEtienne Carriere #include <sys/queue.h> 284b5e93edSEtienne Carriere #include <trace.h> 294b5e93edSEtienne Carriere #include <util.h> 304b5e93edSEtienne Carriere 311001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 321001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 331001585eSEtienne Carriere #endif 341001585eSEtienne Carriere 354b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 364b5e93edSEtienne Carriere 375eed568cSGatien Chevallier #define GPIO_MODER_OFFSET U(0x00) 385eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET U(0x04) 395eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET U(0x08) 405eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET U(0x0c) 415eed568cSGatien Chevallier #define GPIO_IDR_OFFSET U(0x10) 425eed568cSGatien Chevallier #define GPIO_ODR_OFFSET U(0x14) 435eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET U(0x18) 445eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET U(0x20) 455eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET U(0x24) 465eed568cSGatien Chevallier #define GPIO_SECR_OFFSET U(0x30) 47*bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET U(0x34) 48*bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET U(0x38) 49*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x) (U(0x50) + U(0x8) * (x)) 50*bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x) (U(0x54) + U(0x8) * (x)) 514b5e93edSEtienne Carriere 525eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT U(0x8) 534b5e93edSEtienne Carriere 54*bd03c8c3SGatien Chevallier /* 55*bd03c8c3SGatien Chevallier * CIDCFGR register bitfields 56*bd03c8c3SGatien Chevallier */ 57*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK GENMASK_32(23, 16) 58*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK GENMASK_32(6, 4) 59*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK (_CIDCFGR_CFEN | _CIDCFGR_SEMEN | \ 60*bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SCID_MASK | \ 61*bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SEMWL_MASK) 62*bd03c8c3SGatien Chevallier 63*bd03c8c3SGatien Chevallier /* 64*bd03c8c3SGatien Chevallier * PRIVCFGR register bitfields 65*bd03c8c3SGatien Chevallier */ 66*bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK GENMASK_32(15, 0) 67*bd03c8c3SGatien Chevallier 68*bd03c8c3SGatien Chevallier /* 69*bd03c8c3SGatien Chevallier * SECCFGR register bitfields 70*bd03c8c3SGatien Chevallier */ 71*bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK GENMASK_32(15, 0) 72*bd03c8c3SGatien Chevallier 73*bd03c8c3SGatien Chevallier /* 74*bd03c8c3SGatien Chevallier * RCFGLOCKR register bitfields 75*bd03c8c3SGatien Chevallier */ 76*bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK GENMASK_32(15, 0) 77*bd03c8c3SGatien Chevallier 78*bd03c8c3SGatien Chevallier /* 79*bd03c8c3SGatien Chevallier * SEMCR register bitfields 80*bd03c8c3SGatien Chevallier */ 81*bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M GENMASK_32(6, 4) 82*bd03c8c3SGatien Chevallier 834b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 844b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 854b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 86729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 874b5e93edSEtienne Carriere 885eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT U(12) 894b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 905eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT U(8) 914b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 924b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 934b5e93edSEtienne Carriere 949818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 959818a481SEtienne Carriere 9669715ce9SEtienne Carriere #define GPIO_MODE_INPUT U(0x0) 9769715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT U(0x1) 9869715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE U(0x2) 9969715ce9SEtienne Carriere #define GPIO_MODE_ANALOG U(0x3) 10069715ce9SEtienne Carriere 10169715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL U(0x0) 10269715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN U(0x1) 10369715ce9SEtienne Carriere 10469715ce9SEtienne Carriere #define GPIO_OSPEED_LOW U(0x0) 10569715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM U(0x1) 10669715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH U(0x2) 10769715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH U(0x3) 10869715ce9SEtienne Carriere 10969715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL U(0x0) 11069715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP U(0x1) 11169715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN U(0x2) 11269715ce9SEtienne Carriere 11369715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW U(0x0) 11469715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH U(0x1) 11569715ce9SEtienne Carriere 116*bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED U(3) 117*bd03c8c3SGatien Chevallier 11869715ce9SEtienne Carriere /* 11969715ce9SEtienne Carriere * GPIO configuration description structured as single 16bit word 12069715ce9SEtienne Carriere * for efficient save/restore when GPIO pin suspends or resumes. 12169715ce9SEtienne Carriere * 12269715ce9SEtienne Carriere * @mode: One of GPIO_MODE_* 12369715ce9SEtienne Carriere * @otype: One of GPIO_OTYPE_* 12469715ce9SEtienne Carriere * @ospeed: One of GPIO_OSPEED_* 12569715ce9SEtienne Carriere * @pupd: One of GPIO_PUPD_* 12669715ce9SEtienne Carriere * @od: One of GPIO_OD_* 12769715ce9SEtienne Carriere * @af: Alternate function numerical ID between 0 and 15 12869715ce9SEtienne Carriere */ 12969715ce9SEtienne Carriere struct gpio_cfg { 13069715ce9SEtienne Carriere uint16_t mode: 2; 13169715ce9SEtienne Carriere uint16_t otype: 1; 13269715ce9SEtienne Carriere uint16_t ospeed: 2; 13369715ce9SEtienne Carriere uint16_t pupd: 2; 13469715ce9SEtienne Carriere uint16_t od: 1; 13569715ce9SEtienne Carriere uint16_t af: 4; 13669715ce9SEtienne Carriere }; 13769715ce9SEtienne Carriere 13869715ce9SEtienne Carriere /* 13969715ce9SEtienne Carriere * Description of a pin and its muxing 14069715ce9SEtienne Carriere * 14169715ce9SEtienne Carriere * @bank: GPIO bank identifier as assigned by the platform 14269715ce9SEtienne Carriere * @pin: Pin number in the GPIO bank 14369715ce9SEtienne Carriere * @cfg: Pin configuration 14469715ce9SEtienne Carriere */ 14569715ce9SEtienne Carriere struct stm32_pinctrl { 14669715ce9SEtienne Carriere uint8_t bank; 14769715ce9SEtienne Carriere uint8_t pin; 14869715ce9SEtienne Carriere struct gpio_cfg cfg; 14969715ce9SEtienne Carriere }; 15069715ce9SEtienne Carriere 151b38386fbSEtienne Carriere /* 152b38386fbSEtienne Carriere * struct stm32_pinctrl_array - Array of pins in a pin control state 153b38386fbSEtienne Carriere * @count: Number of cells in @pinctrl 154b38386fbSEtienne Carriere * @pinctrl: Pin control configuration 155b38386fbSEtienne Carriere */ 156b38386fbSEtienne Carriere struct stm32_pinctrl_array { 157b38386fbSEtienne Carriere size_t count; 158b38386fbSEtienne Carriere struct stm32_pinctrl pinctrl[]; 159b38386fbSEtienne Carriere }; 160b38386fbSEtienne Carriere 1619818a481SEtienne Carriere /** 1629818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 1639818a481SEtienne Carriere * 1649818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 1659818a481SEtienne Carriere * @clock: clock identifier. 166420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 1679818a481SEtienne Carriere * @ngpios: number of GPIOs. 1689818a481SEtienne Carriere * @bank_id: Id of the bank. 1699818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 170*bd03c8c3SGatien Chevallier * @rif_cfg: RIF configuration data 171*bd03c8c3SGatien Chevallier * @seccfgr: non-RIF bank secure configuration data 172*bd03c8c3SGatien Chevallier * @sec_support: True if bank supports pin security protection, else false 173*bd03c8c3SGatien Chevallier * @ready: True if configuration is applied, else false 174*bd03c8c3SGatien Chevallier * @is_tdcid: True if OP-TEE runs as Trusted Domain CID 1759818a481SEtienne Carriere * @link: Link in bank list 1769818a481SEtienne Carriere */ 1779818a481SEtienne Carriere struct stm32_gpio_bank { 1789818a481SEtienne Carriere vaddr_t base; 1799818a481SEtienne Carriere struct clk *clock; 180420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 1819818a481SEtienne Carriere unsigned int ngpios; 1829818a481SEtienne Carriere unsigned int bank_id; 1839818a481SEtienne Carriere unsigned int lock; 184*bd03c8c3SGatien Chevallier struct rif_conf_data *rif_cfg; 185*bd03c8c3SGatien Chevallier uint32_t seccfgr; 186b4893304SGatien Chevallier bool sec_support; 187*bd03c8c3SGatien Chevallier bool ready; 188*bd03c8c3SGatien Chevallier bool is_tdcid; 1899818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 1909818a481SEtienne Carriere }; 1919818a481SEtienne Carriere 192b4893304SGatien Chevallier /** 193e569f6adSEtienne Carriere * Compatibility information of supported banks 194b4893304SGatien Chevallier * 195b4893304SGatien Chevallier * @gpioz: True if bank is a GPIOZ bank 196b4893304SGatien Chevallier * @secure_control: Identify GPIO security bank capability. 197*bd03c8c3SGatien Chevallier * @secure_extended: Identify RIF presence. 198e569f6adSEtienne Carriere */ 199e569f6adSEtienne Carriere struct bank_compat { 200e569f6adSEtienne Carriere bool gpioz; 201b4893304SGatien Chevallier bool secure_control; 202*bd03c8c3SGatien Chevallier bool secure_extended; 203e569f6adSEtienne Carriere }; 204e569f6adSEtienne Carriere 2054b5e93edSEtienne Carriere static unsigned int gpio_lock; 2064b5e93edSEtienne Carriere 2079818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 2089818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 2099818a481SEtienne Carriere 210420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 211420a32c5SEtienne Carriere 212420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 213420a32c5SEtienne Carriere { 214420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 215420a32c5SEtienne Carriere } 216420a32c5SEtienne Carriere 217420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 218420a32c5SEtienne Carriere unsigned int gpio_pin) 219420a32c5SEtienne Carriere { 220420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 221420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 222420a32c5SEtienne Carriere unsigned int reg_offset = 0; 223420a32c5SEtienne Carriere unsigned int mode = 0; 224420a32c5SEtienne Carriere 225420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2262fd102ebSEtienne Carriere 2272fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2282fd102ebSEtienne Carriere panic(); 229420a32c5SEtienne Carriere 230420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 231420a32c5SEtienne Carriere GPIO_MODE_MASK; 232420a32c5SEtienne Carriere 233420a32c5SEtienne Carriere switch (mode) { 234420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 235420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 236420a32c5SEtienne Carriere break; 237420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 238420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 239420a32c5SEtienne Carriere break; 240420a32c5SEtienne Carriere default: 241420a32c5SEtienne Carriere panic(); 242420a32c5SEtienne Carriere } 243420a32c5SEtienne Carriere 244420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 245420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 246420a32c5SEtienne Carriere else 247420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 248420a32c5SEtienne Carriere 249420a32c5SEtienne Carriere clk_disable(bank->clock); 250420a32c5SEtienne Carriere 251420a32c5SEtienne Carriere return level; 252420a32c5SEtienne Carriere } 253420a32c5SEtienne Carriere 254420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 255420a32c5SEtienne Carriere enum gpio_level level) 256420a32c5SEtienne Carriere { 257420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 258420a32c5SEtienne Carriere 259420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2602fd102ebSEtienne Carriere 2612fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2622fd102ebSEtienne Carriere panic(); 263420a32c5SEtienne Carriere 264420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 265420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 266420a32c5SEtienne Carriere 267420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 268420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 269420a32c5SEtienne Carriere else 270420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 271420a32c5SEtienne Carriere 272420a32c5SEtienne Carriere clk_disable(bank->clock); 273420a32c5SEtienne Carriere } 274420a32c5SEtienne Carriere 275420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 276420a32c5SEtienne Carriere unsigned int gpio_pin) 277420a32c5SEtienne Carriere { 278420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 279420a32c5SEtienne Carriere uint32_t mode = 0; 280420a32c5SEtienne Carriere 281420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2822fd102ebSEtienne Carriere 2832fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2842fd102ebSEtienne Carriere panic(); 285420a32c5SEtienne Carriere 286420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 287420a32c5SEtienne Carriere GPIO_MODE_MASK; 288420a32c5SEtienne Carriere 289420a32c5SEtienne Carriere clk_disable(bank->clock); 290420a32c5SEtienne Carriere 291420a32c5SEtienne Carriere switch (mode) { 292420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 293420a32c5SEtienne Carriere return GPIO_DIR_IN; 294420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 295420a32c5SEtienne Carriere return GPIO_DIR_OUT; 296420a32c5SEtienne Carriere default: 297420a32c5SEtienne Carriere panic(); 298420a32c5SEtienne Carriere } 299420a32c5SEtienne Carriere } 300420a32c5SEtienne Carriere 301420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 302420a32c5SEtienne Carriere unsigned int gpio_pin, 303420a32c5SEtienne Carriere enum gpio_dir direction) 304420a32c5SEtienne Carriere { 305420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 306420a32c5SEtienne Carriere uint32_t exceptions = 0; 307420a32c5SEtienne Carriere uint32_t mode = 0; 308420a32c5SEtienne Carriere 309420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 310420a32c5SEtienne Carriere 311420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 312420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 313420a32c5SEtienne Carriere else 314420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 315420a32c5SEtienne Carriere 3162fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 3172fd102ebSEtienne Carriere panic(); 318420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 319420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 320420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 321420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 322420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 323420a32c5SEtienne Carriere clk_disable(bank->clock); 324420a32c5SEtienne Carriere } 325420a32c5SEtienne Carriere 326420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 327420a32c5SEtienne Carriere struct gpio *gpio) 328420a32c5SEtienne Carriere { 329420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 330420a32c5SEtienne Carriere free(gpio); 331420a32c5SEtienne Carriere } 332420a32c5SEtienne Carriere 333420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 334420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 335420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 336420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 337420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 338420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 339420a32c5SEtienne Carriere }; 340420a32c5SEtienne Carriere 341420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 342420a32c5SEtienne Carriere { 343420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 344420a32c5SEtienne Carriere } 345420a32c5SEtienne Carriere 346077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 3474b5e93edSEtienne Carriere { 348077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 3494b5e93edSEtienne Carriere 350077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 351077d486eSEtienne Carriere if (bank_id == bank->bank_id) 352077d486eSEtienne Carriere return bank; 353077d486eSEtienne Carriere 354077d486eSEtienne Carriere panic(); 355077d486eSEtienne Carriere } 356077d486eSEtienne Carriere 357077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 358b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin, 359b38386fbSEtienne Carriere struct gpio_cfg *cfg) 360077d486eSEtienne Carriere { 361077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 362077d486eSEtienne Carriere 363077d486eSEtienne Carriere if (clk_enable(bank->clock)) 364077d486eSEtienne Carriere panic(); 3654b5e93edSEtienne Carriere 3664b5e93edSEtienne Carriere /* 3674b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 3684b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 3694b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 3704b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 3714b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 3724b5e93edSEtienne Carriere */ 373077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 3744b5e93edSEtienne Carriere GPIO_MODE_MASK; 3754b5e93edSEtienne Carriere 376077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 3774b5e93edSEtienne Carriere 378077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 379077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 3804b5e93edSEtienne Carriere 381077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 3824b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 3834b5e93edSEtienne Carriere 384077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 3854b5e93edSEtienne Carriere 3864b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 387077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 388077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 3894b5e93edSEtienne Carriere else 390077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 3914b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 3924b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 3934b5e93edSEtienne Carriere 394077d486eSEtienne Carriere clk_disable(bank->clock); 3954b5e93edSEtienne Carriere } 3964b5e93edSEtienne Carriere 3974b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 398077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 3994b5e93edSEtienne Carriere { 400077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 40198dfcedaSEtienne Carriere uint32_t exceptions = 0; 4024b5e93edSEtienne Carriere 403077d486eSEtienne Carriere if (clk_enable(bank->clock)) 404077d486eSEtienne Carriere panic(); 40598dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 4064b5e93edSEtienne Carriere 4074b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 408077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 409bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 410bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 4114b5e93edSEtienne Carriere 4124b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 413077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 414bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 4154b5e93edSEtienne Carriere 4164b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 417077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 418bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 419bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 4204b5e93edSEtienne Carriere 4214b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 422077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 423bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 4244b5e93edSEtienne Carriere 4254b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 4264b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 427077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 428bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 429bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 4304b5e93edSEtienne Carriere } else { 4314b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 4324b5e93edSEtienne Carriere 433077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 434bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 435bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 4364b5e93edSEtienne Carriere } 4374b5e93edSEtienne Carriere 4384b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 439077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 4404b5e93edSEtienne Carriere 441c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 44298dfcedaSEtienne Carriere clk_disable(bank->clock); 4434b5e93edSEtienne Carriere } 4444b5e93edSEtienne Carriere 4454b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 446b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node, 4474b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 4484b5e93edSEtienne Carriere { 449b38386fbSEtienne Carriere const fdt32_t *cuint = NULL; 450b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL; 45110bcbd6cSEtienne Carriere int len = 0; 45210bcbd6cSEtienne Carriere uint32_t i = 0; 4534b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 4544b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 4554b5e93edSEtienne Carriere size_t found = 0; 4564b5e93edSEtienne Carriere 4574b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 4584b5e93edSEtienne Carriere if (!cuint) 4594b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 4604b5e93edSEtienne Carriere 4614b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 4624b5e93edSEtienne Carriere if (slewrate) 4634b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 4644b5e93edSEtienne Carriere 4654b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 4664b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 4674b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 4684b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 4694b5e93edSEtienne Carriere 4704b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 47110bcbd6cSEtienne Carriere uint32_t pincfg = 0; 47210bcbd6cSEtienne Carriere uint32_t bank = 0; 47310bcbd6cSEtienne Carriere uint32_t pin = 0; 47410bcbd6cSEtienne Carriere uint32_t mode = 0; 4754b5e93edSEtienne Carriere uint32_t alternate = 0; 476322cf9e3SEtienne Carriere uint32_t odata = 0; 4774b5e93edSEtienne Carriere bool opendrain = false; 4784b5e93edSEtienne Carriere 4794b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 4804b5e93edSEtienne Carriere cuint++; 4814b5e93edSEtienne Carriere 4824b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 4834b5e93edSEtienne Carriere 4844b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 4854b5e93edSEtienne Carriere 4864b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 4874b5e93edSEtienne Carriere 4884b5e93edSEtienne Carriere switch (mode) { 4894b5e93edSEtienne Carriere case 0: 4904b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 4914b5e93edSEtienne Carriere break; 4924b5e93edSEtienne Carriere case 1: 4934b5e93edSEtienne Carriere case 2: 4944b5e93edSEtienne Carriere case 3: 4954b5e93edSEtienne Carriere case 4: 4964b5e93edSEtienne Carriere case 5: 4974b5e93edSEtienne Carriere case 6: 4984b5e93edSEtienne Carriere case 7: 4994b5e93edSEtienne Carriere case 8: 5004b5e93edSEtienne Carriere case 9: 5014b5e93edSEtienne Carriere case 10: 5024b5e93edSEtienne Carriere case 11: 5034b5e93edSEtienne Carriere case 12: 5044b5e93edSEtienne Carriere case 13: 5054b5e93edSEtienne Carriere case 14: 5064b5e93edSEtienne Carriere case 15: 5074b5e93edSEtienne Carriere case 16: 5084b5e93edSEtienne Carriere alternate = mode - 1U; 5094b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 5104b5e93edSEtienne Carriere break; 5114b5e93edSEtienne Carriere case 17: 5124b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 5134b5e93edSEtienne Carriere break; 5144b5e93edSEtienne Carriere default: 5154b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 5164b5e93edSEtienne Carriere break; 5174b5e93edSEtienne Carriere } 5184b5e93edSEtienne Carriere 5194b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 5204b5e93edSEtienne Carriere opendrain = true; 5214b5e93edSEtienne Carriere 522322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 523322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 524322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 525322cf9e3SEtienne Carriere odata = 1; 526322cf9e3SEtienne Carriere } 527322cf9e3SEtienne Carriere 528322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 529322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 530322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 531322cf9e3SEtienne Carriere odata = 0; 532322cf9e3SEtienne Carriere } 533322cf9e3SEtienne Carriere 5344b5e93edSEtienne Carriere if (found < count) { 5354b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 5364b5e93edSEtienne Carriere 5374b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 5384b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 539b38386fbSEtienne Carriere ref->cfg.mode = mode; 540b38386fbSEtienne Carriere if (opendrain) 541b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN; 542b38386fbSEtienne Carriere else 543b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL; 544b38386fbSEtienne Carriere ref->cfg.ospeed = speed; 545b38386fbSEtienne Carriere ref->cfg.pupd = pull; 546b38386fbSEtienne Carriere ref->cfg.od = odata; 547b38386fbSEtienne Carriere ref->cfg.af = alternate; 5484b5e93edSEtienne Carriere } 5494b5e93edSEtienne Carriere 5504b5e93edSEtienne Carriere found++; 5514b5e93edSEtienne Carriere } 5524b5e93edSEtienne Carriere 5534b5e93edSEtienne Carriere return (int)found; 5544b5e93edSEtienne Carriere } 5554b5e93edSEtienne Carriere 556b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data, 557b357d34fSEtienne Carriere struct gpio **out_gpio) 558420a32c5SEtienne Carriere { 559b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 560420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 561420a32c5SEtienne Carriere struct gpio *gpio = NULL; 562420a32c5SEtienne Carriere unsigned int shift_1b = 0; 563420a32c5SEtienne Carriere unsigned int shift_2b = 0; 564420a32c5SEtienne Carriere uint32_t exceptions = 0; 565420a32c5SEtienne Carriere uint32_t otype = 0; 566420a32c5SEtienne Carriere uint32_t pupd = 0; 567420a32c5SEtienne Carriere uint32_t mode = 0; 568420a32c5SEtienne Carriere 569b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio); 570b357d34fSEtienne Carriere if (res) 571b357d34fSEtienne Carriere return res; 572420a32c5SEtienne Carriere 573420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 574420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 575420a32c5SEtienne Carriere free(gpio); 576b357d34fSEtienne Carriere return TEE_ERROR_GENERIC; 577420a32c5SEtienne Carriere } 578420a32c5SEtienne Carriere 579420a32c5SEtienne Carriere shift_1b = gpio->pin; 580420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 581420a32c5SEtienne Carriere 582420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 583420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 584420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 585420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 586420a32c5SEtienne Carriere else 587420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 588420a32c5SEtienne Carriere 589420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 590420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 591420a32c5SEtienne Carriere else 592420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 593420a32c5SEtienne Carriere 594420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 595420a32c5SEtienne Carriere panic(); 596420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 597420a32c5SEtienne Carriere 598420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 599420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 600420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 601420a32c5SEtienne Carriere 602420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 603420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 604420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 605420a32c5SEtienne Carriere 606420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 607420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 608420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 609420a32c5SEtienne Carriere 610420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 611420a32c5SEtienne Carriere clk_disable(bank->clock); 612420a32c5SEtienne Carriere 613420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 614420a32c5SEtienne Carriere 615b357d34fSEtienne Carriere *out_gpio = gpio; 616420a32c5SEtienne Carriere 617b357d34fSEtienne Carriere return TEE_SUCCESS; 618420a32c5SEtienne Carriere } 619420a32c5SEtienne Carriere 6209818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 6219818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 6229818a481SEtienne Carriere { 6239818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 6249818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6259818a481SEtienne Carriere int len = 0; 6269818a481SEtienne Carriere 6279818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 6289818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 6299818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 6309818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 6319818a481SEtienne Carriere 6329818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 6339818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 6349818a481SEtienne Carriere panic("Wrong st,bank-name property"); 6359818a481SEtienne Carriere 6369818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 6379818a481SEtienne Carriere } 6389818a481SEtienne Carriere 6399818a481SEtienne Carriere /* 6409818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 6419818a481SEtienne Carriere * registered in the GPIO bank link. 6429818a481SEtienne Carriere */ 6439818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 6449818a481SEtienne Carriere { 6459818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 6469818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6479818a481SEtienne Carriere 6489818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 6499818a481SEtienne Carriere if (bank->bank_id == bank_id) 6509818a481SEtienne Carriere return true; 6519818a481SEtienne Carriere 6529818a481SEtienne Carriere return false; 6539818a481SEtienne Carriere } 6549818a481SEtienne Carriere 655*bd03c8c3SGatien Chevallier static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank) 656*bd03c8c3SGatien Chevallier { 657*bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 658*bd03c8c3SGatien Chevallier uint32_t cidcfgr = 0; 659*bd03c8c3SGatien Chevallier unsigned int i = 0; 660*bd03c8c3SGatien Chevallier 661*bd03c8c3SGatien Chevallier if (!bank->rif_cfg) 662*bd03c8c3SGatien Chevallier return TEE_SUCCESS; 663*bd03c8c3SGatien Chevallier 664*bd03c8c3SGatien Chevallier if (clk_enable(bank->clock)) 665*bd03c8c3SGatien Chevallier panic(); 666*bd03c8c3SGatien Chevallier 667*bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) { 668*bd03c8c3SGatien Chevallier if (!(BIT(i) & bank->rif_cfg->access_mask[0])) 669*bd03c8c3SGatien Chevallier continue; 670*bd03c8c3SGatien Chevallier 671*bd03c8c3SGatien Chevallier /* 672*bd03c8c3SGatien Chevallier * When TDCID, OP-TEE should be the one to set the CID filtering 673*bd03c8c3SGatien Chevallier * configuration. Clearing previous configuration prevents 674*bd03c8c3SGatien Chevallier * undesired events during the only legitimate configuration. 675*bd03c8c3SGatien Chevallier */ 676*bd03c8c3SGatien Chevallier if (bank->is_tdcid) 677*bd03c8c3SGatien Chevallier io_clrbits32(bank->base + GPIO_CIDCFGR(i), 678*bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK); 679*bd03c8c3SGatien Chevallier 680*bd03c8c3SGatien Chevallier cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i)); 681*bd03c8c3SGatien Chevallier 682*bd03c8c3SGatien Chevallier /* Check if the controller is in semaphore mode */ 683*bd03c8c3SGatien Chevallier if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) 684*bd03c8c3SGatien Chevallier continue; 685*bd03c8c3SGatien Chevallier 686*bd03c8c3SGatien Chevallier /* If not TDCID, we want to acquire semaphores assigned to us */ 687*bd03c8c3SGatien Chevallier res = stm32_rif_acquire_semaphore(bank->base + GPIO_SEMCR(i), 688*bd03c8c3SGatien Chevallier GPIO_MAX_CID_SUPPORTED); 689*bd03c8c3SGatien Chevallier if (res) { 690*bd03c8c3SGatien Chevallier EMSG("Could not acquire semaphore for pin %c%u", 691*bd03c8c3SGatien Chevallier 'A' + bank->bank_id, i); 692*bd03c8c3SGatien Chevallier goto out; 693*bd03c8c3SGatien Chevallier } 694*bd03c8c3SGatien Chevallier } 695*bd03c8c3SGatien Chevallier 696*bd03c8c3SGatien Chevallier /* Security and privilege RIF configuration */ 697*bd03c8c3SGatien Chevallier io_clrsetbits32(bank->base + GPIO_PRIVCFGR_OFFSET, GPIO_PRIVCFGR_MASK, 698*bd03c8c3SGatien Chevallier bank->rif_cfg->priv_conf[0]); 699*bd03c8c3SGatien Chevallier io_clrsetbits32(bank->base + GPIO_SECR_OFFSET, GPIO_SECCFGR_MASK, 700*bd03c8c3SGatien Chevallier bank->rif_cfg->sec_conf[0]); 701*bd03c8c3SGatien Chevallier 702*bd03c8c3SGatien Chevallier if (!bank->is_tdcid) { 703*bd03c8c3SGatien Chevallier res = TEE_SUCCESS; 704*bd03c8c3SGatien Chevallier goto out; 705*bd03c8c3SGatien Chevallier } 706*bd03c8c3SGatien Chevallier 707*bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) { 708*bd03c8c3SGatien Chevallier if (!(BIT(i) & bank->rif_cfg->access_mask[0])) 709*bd03c8c3SGatien Chevallier continue; 710*bd03c8c3SGatien Chevallier 711*bd03c8c3SGatien Chevallier io_clrsetbits32(bank->base + GPIO_CIDCFGR(i), 712*bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK, 713*bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs[i]); 714*bd03c8c3SGatien Chevallier 715*bd03c8c3SGatien Chevallier cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i)); 716*bd03c8c3SGatien Chevallier 717*bd03c8c3SGatien Chevallier /* 718*bd03c8c3SGatien Chevallier * Take semaphore if the resource is in semaphore mode 719*bd03c8c3SGatien Chevallier * and secured. 720*bd03c8c3SGatien Chevallier */ 721*bd03c8c3SGatien Chevallier if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1) || 722*bd03c8c3SGatien Chevallier !(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) { 723*bd03c8c3SGatien Chevallier res = stm32_rif_release_semaphore(bank->base + 724*bd03c8c3SGatien Chevallier GPIO_SEMCR(i), 725*bd03c8c3SGatien Chevallier GPIO_MAX_CID_SUPPORTED); 726*bd03c8c3SGatien Chevallier if (res) { 727*bd03c8c3SGatien Chevallier EMSG("Could not release semaphore for pin %c%u", 728*bd03c8c3SGatien Chevallier 'A' + bank->bank_id, i); 729*bd03c8c3SGatien Chevallier goto out; 730*bd03c8c3SGatien Chevallier } 731*bd03c8c3SGatien Chevallier } else { 732*bd03c8c3SGatien Chevallier res = stm32_rif_acquire_semaphore(bank->base + 733*bd03c8c3SGatien Chevallier GPIO_SEMCR(i), 734*bd03c8c3SGatien Chevallier GPIO_MAX_CID_SUPPORTED); 735*bd03c8c3SGatien Chevallier if (res) { 736*bd03c8c3SGatien Chevallier EMSG("Could not acquire semaphore for pin %c%u", 737*bd03c8c3SGatien Chevallier 'A' + bank->bank_id, i); 738*bd03c8c3SGatien Chevallier goto out; 739*bd03c8c3SGatien Chevallier } 740*bd03c8c3SGatien Chevallier } 741*bd03c8c3SGatien Chevallier } 742*bd03c8c3SGatien Chevallier 743*bd03c8c3SGatien Chevallier /* 744*bd03c8c3SGatien Chevallier * Lock RIF configuration if configured. This cannot be undone until 745*bd03c8c3SGatien Chevallier * next reset. 746*bd03c8c3SGatien Chevallier */ 747*bd03c8c3SGatien Chevallier io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET, 748*bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf[0]); 749*bd03c8c3SGatien Chevallier 750*bd03c8c3SGatien Chevallier if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) { 751*bd03c8c3SGatien Chevallier /* Check that RIF config are applied, panic otherwise */ 752*bd03c8c3SGatien Chevallier if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) & 753*bd03c8c3SGatien Chevallier bank->rif_cfg->access_mask[0]) != 754*bd03c8c3SGatien Chevallier bank->rif_cfg->priv_conf[0]) { 755*bd03c8c3SGatien Chevallier EMSG("GPIO bank%c priv conf is incorrect", 756*bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 757*bd03c8c3SGatien Chevallier panic(); 758*bd03c8c3SGatien Chevallier } 759*bd03c8c3SGatien Chevallier 760*bd03c8c3SGatien Chevallier if ((io_read32(bank->base + GPIO_SECR_OFFSET) & 761*bd03c8c3SGatien Chevallier bank->rif_cfg->access_mask[0]) != 762*bd03c8c3SGatien Chevallier bank->rif_cfg->sec_conf[0]) { 763*bd03c8c3SGatien Chevallier EMSG("GPIO bank %c sec conf is incorrect", 764*bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 765*bd03c8c3SGatien Chevallier panic(); 766*bd03c8c3SGatien Chevallier } 767*bd03c8c3SGatien Chevallier } 768*bd03c8c3SGatien Chevallier 769*bd03c8c3SGatien Chevallier res = TEE_SUCCESS; 770*bd03c8c3SGatien Chevallier out: 771*bd03c8c3SGatien Chevallier clk_disable(bank->clock); 772*bd03c8c3SGatien Chevallier 773*bd03c8c3SGatien Chevallier return res; 774*bd03c8c3SGatien Chevallier } 775*bd03c8c3SGatien Chevallier 776*bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank, 777*bd03c8c3SGatien Chevallier const void *fdt, int node) 778*bd03c8c3SGatien Chevallier { 779*bd03c8c3SGatien Chevallier unsigned int i = 0; 780*bd03c8c3SGatien Chevallier unsigned int nb_rif_conf = 0; 781*bd03c8c3SGatien Chevallier int lenp = 0; 782*bd03c8c3SGatien Chevallier const fdt32_t *cuint = NULL; 783*bd03c8c3SGatien Chevallier 784*bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); 785*bd03c8c3SGatien Chevallier if (!cuint) { 786*bd03c8c3SGatien Chevallier DMSG("No RIF configuration available"); 787*bd03c8c3SGatien Chevallier return; 788*bd03c8c3SGatien Chevallier } 789*bd03c8c3SGatien Chevallier 790*bd03c8c3SGatien Chevallier bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg)); 791*bd03c8c3SGatien Chevallier if (!bank->rif_cfg) 792*bd03c8c3SGatien Chevallier panic(); 793*bd03c8c3SGatien Chevallier 794*bd03c8c3SGatien Chevallier bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t)); 795*bd03c8c3SGatien Chevallier if (!bank->rif_cfg->sec_conf) 796*bd03c8c3SGatien Chevallier panic(); 797*bd03c8c3SGatien Chevallier 798*bd03c8c3SGatien Chevallier nb_rif_conf = (unsigned int)(lenp / sizeof(uint32_t)); 799*bd03c8c3SGatien Chevallier assert(nb_rif_conf <= bank->ngpios); 800*bd03c8c3SGatien Chevallier 801*bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t)); 802*bd03c8c3SGatien Chevallier bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t)); 803*bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t)); 804*bd03c8c3SGatien Chevallier bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t)); 805*bd03c8c3SGatien Chevallier if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask || 806*bd03c8c3SGatien Chevallier !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf) 807*bd03c8c3SGatien Chevallier panic("Missing memory capacity for GPIOS RIF configuration"); 808*bd03c8c3SGatien Chevallier 809*bd03c8c3SGatien Chevallier for (i = 0; i < nb_rif_conf; i++) 810*bd03c8c3SGatien Chevallier stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg, 811*bd03c8c3SGatien Chevallier GPIO_MAX_CID_SUPPORTED, bank->ngpios); 812*bd03c8c3SGatien Chevallier } 813*bd03c8c3SGatien Chevallier 8149818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 8159818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 816e569f6adSEtienne Carriere const void *compat_data, 8179818a481SEtienne Carriere int range_offset, 8189818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 8199818a481SEtienne Carriere { 820e569f6adSEtienne Carriere const struct bank_compat *compat = compat_data; 8219818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 8229818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 8239818a481SEtienne Carriere const fdt32_t *cuint = NULL; 8249818a481SEtienne Carriere struct io_pa_va pa_va = { }; 8259818a481SEtienne Carriere struct clk *clk = NULL; 8269818a481SEtienne Carriere size_t blen = 0; 8279818a481SEtienne Carriere paddr_t pa = 0; 8289818a481SEtienne Carriere int len = 0; 8299818a481SEtienne Carriere int i = 0; 8309818a481SEtienne Carriere 8319818a481SEtienne Carriere assert(out_bank); 8329818a481SEtienne Carriere 8339818a481SEtienne Carriere /* Probe deferrable devices first */ 8349818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 8359818a481SEtienne Carriere if (res) 8369818a481SEtienne Carriere return res; 8379818a481SEtienne Carriere 8389818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 8399818a481SEtienne Carriere if (!bank) 8409818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 8419818a481SEtienne Carriere 842*bd03c8c3SGatien Chevallier if (compat->secure_extended) { 843*bd03c8c3SGatien Chevallier res = stm32_rifsc_check_tdcid(&bank->is_tdcid); 844*bd03c8c3SGatien Chevallier if (res) { 845*bd03c8c3SGatien Chevallier free(bank); 846*bd03c8c3SGatien Chevallier return res; 847*bd03c8c3SGatien Chevallier } 848*bd03c8c3SGatien Chevallier } 849*bd03c8c3SGatien Chevallier 8509818a481SEtienne Carriere /* 8519818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 8529818a481SEtienne Carriere * but consider also the "ranges" translation property 8539818a481SEtienne Carriere */ 8549818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 8559818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 8569818a481SEtienne Carriere panic("missing reg property"); 8579818a481SEtienne Carriere 8589818a481SEtienne Carriere pa_va.pa = pa + range_offset; 8599818a481SEtienne Carriere 8609818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 8619818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 8629818a481SEtienne Carriere panic("missing reg size property"); 8639818a481SEtienne Carriere 8649818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 8659818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 8669818a481SEtienne Carriere bank->clock = clk; 867420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 868b4893304SGatien Chevallier bank->sec_support = compat->secure_control; 8699818a481SEtienne Carriere 8709818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 8719818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 8729818a481SEtienne Carriere len /= sizeof(*cuint); 8739818a481SEtienne Carriere if (len % 4) 8749818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 8759818a481SEtienne Carriere 8769818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 8779818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 8789818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 8799818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 8809818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 8819818a481SEtienne Carriere cuint += 4; 8829818a481SEtienne Carriere } 8839818a481SEtienne Carriere 884*bd03c8c3SGatien Chevallier if (compat->secure_extended) { 885*bd03c8c3SGatien Chevallier /* RIF configuration */ 886*bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen); 887*bd03c8c3SGatien Chevallier 888*bd03c8c3SGatien Chevallier stm32_parse_gpio_rif_conf(bank, fdt, node); 889*bd03c8c3SGatien Chevallier } else if (bank->sec_support) { 890*bd03c8c3SGatien Chevallier /* Secure configuration */ 891*bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen); 892*bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", NULL); 893*bd03c8c3SGatien Chevallier if (cuint) 894*bd03c8c3SGatien Chevallier bank->seccfgr = fdt32_to_cpu(*cuint); 895*bd03c8c3SGatien Chevallier else 896*bd03c8c3SGatien Chevallier DMSG("GPIO bank %c assigned to non-secure", 897*bd03c8c3SGatien Chevallier bank->bank_id + 'A'); 898*bd03c8c3SGatien Chevallier } else { 899*bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_nsec(&pa_va, blen); 900*bd03c8c3SGatien Chevallier } 901*bd03c8c3SGatien Chevallier 902e569f6adSEtienne Carriere if (compat->gpioz) 903e569f6adSEtienne Carriere stm32mp_register_gpioz_pin_count(bank->ngpios); 904e569f6adSEtienne Carriere 9059818a481SEtienne Carriere *out_bank = bank; 906*bd03c8c3SGatien Chevallier 9079818a481SEtienne Carriere return TEE_SUCCESS; 9089818a481SEtienne Carriere } 9099818a481SEtienne Carriere 910*bd03c8c3SGatien Chevallier /* Parse a pinctrl node to register the GPIO banks it describes */ 9110e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 9129818a481SEtienne Carriere const void *compat_data) 9139818a481SEtienne Carriere { 9149818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 9159818a481SEtienne Carriere const fdt32_t *cuint = NULL; 9169818a481SEtienne Carriere int range_offs = 0; 9179818a481SEtienne Carriere int b_node = 0; 9189818a481SEtienne Carriere int len = 0; 9199818a481SEtienne Carriere 9209818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 9219818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 9229818a481SEtienne Carriere if (!cuint) 9239818a481SEtienne Carriere panic("missing ranges property"); 9249818a481SEtienne Carriere 9259818a481SEtienne Carriere len /= sizeof(*cuint); 9269818a481SEtienne Carriere if (len == 3) 9279818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 9289818a481SEtienne Carriere 9299818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 9309818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 9319818a481SEtienne Carriere if (cuint) { 9329818a481SEtienne Carriere /* 9339818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 9349818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 9359818a481SEtienne Carriere * bank list. 9369818a481SEtienne Carriere */ 9379818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 9389818a481SEtienne Carriere 9399818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 9409818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 9419818a481SEtienne Carriere continue; 9429818a481SEtienne Carriere 9439818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 9449818a481SEtienne Carriere range_offs, &bank); 9459818a481SEtienne Carriere if (res) 9469818a481SEtienne Carriere return res; 9479818a481SEtienne Carriere 948420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 949420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 950420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 951420a32c5SEtienne Carriere if (res) 952420a32c5SEtienne Carriere panic(); 953420a32c5SEtienne Carriere 9549818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 9559818a481SEtienne Carriere } else { 9569818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 9579818a481SEtienne Carriere panic(); 9589818a481SEtienne Carriere } 9599818a481SEtienne Carriere } 9609818a481SEtienne Carriere 9619818a481SEtienne Carriere return TEE_SUCCESS; 9629818a481SEtienne Carriere } 9639818a481SEtienne Carriere 964077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 965077d486eSEtienne Carriere bool secure) 9664b5e93edSEtienne Carriere { 967077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 96898dfcedaSEtienne Carriere uint32_t exceptions = 0; 9694b5e93edSEtienne Carriere 970077d486eSEtienne Carriere if (clk_enable(bank->clock)) 971077d486eSEtienne Carriere panic(); 97298dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 9734b5e93edSEtienne Carriere 9744b5e93edSEtienne Carriere if (secure) 975077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 9764b5e93edSEtienne Carriere else 977077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 9784b5e93edSEtienne Carriere 979c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 98098dfcedaSEtienne Carriere clk_disable(bank->clock); 9814b5e93edSEtienne Carriere } 9820e0435e2SEtienne Carriere 983b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 984b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf) 985b38386fbSEtienne Carriere { 986b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv; 987b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl; 988b38386fbSEtienne Carriere size_t pin_count = ref->count; 989b38386fbSEtienne Carriere size_t n = 0; 990b38386fbSEtienne Carriere 991b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++) 992b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg); 993b38386fbSEtienne Carriere 994b38386fbSEtienne Carriere return TEE_SUCCESS; 995b38386fbSEtienne Carriere } 996b38386fbSEtienne Carriere 997b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf) 998b38386fbSEtienne Carriere { 999b38386fbSEtienne Carriere free(conf); 1000b38386fbSEtienne Carriere } 1001b38386fbSEtienne Carriere 1002b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = { 1003b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply, 1004b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free, 1005b38386fbSEtienne Carriere }; 1006b38386fbSEtienne Carriere 1007b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops); 1008b38386fbSEtienne Carriere 100970ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl, 101070ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin, 101170ac0db5SEtienne Carriere unsigned int *count) 101270ac0db5SEtienne Carriere { 101370ac0db5SEtienne Carriere size_t conf_index = 0; 101470ac0db5SEtienne Carriere size_t pin_count = 0; 101570ac0db5SEtienne Carriere size_t n = 0; 101670ac0db5SEtienne Carriere 101770ac0db5SEtienne Carriere assert(count); 101870ac0db5SEtienne Carriere if (!pinctrl) 101970ac0db5SEtienne Carriere goto out; 102070ac0db5SEtienne Carriere 102170ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 102270ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 102370ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 102470ac0db5SEtienne Carriere 102570ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */ 102670ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 102770ac0db5SEtienne Carriere continue; 102870ac0db5SEtienne Carriere 102970ac0db5SEtienne Carriere if (bank || pin) { 103070ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) { 103170ac0db5SEtienne Carriere if (bank && pin_count < *count) 103270ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank; 103370ac0db5SEtienne Carriere if (pin && pin_count < *count) 103470ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin; 103570ac0db5SEtienne Carriere pin_count++; 103670ac0db5SEtienne Carriere } 103770ac0db5SEtienne Carriere } else { 103870ac0db5SEtienne Carriere pin_count += ref->count; 103970ac0db5SEtienne Carriere } 104070ac0db5SEtienne Carriere } 104170ac0db5SEtienne Carriere 104270ac0db5SEtienne Carriere out: 104370ac0db5SEtienne Carriere *count = pin_count; 104470ac0db5SEtienne Carriere } 104570ac0db5SEtienne Carriere 10467f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure) 10477f823a77SEtienne Carriere { 10487f823a77SEtienne Carriere size_t conf_index = 0; 10497f823a77SEtienne Carriere 10507f823a77SEtienne Carriere if (!pinctrl) 10517f823a77SEtienne Carriere return; 10527f823a77SEtienne Carriere 10537f823a77SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 10547f823a77SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 10557f823a77SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 10567f823a77SEtienne Carriere struct stm32_pinctrl *pc = NULL; 10577f823a77SEtienne Carriere size_t n = 0; 10587f823a77SEtienne Carriere 10597f823a77SEtienne Carriere for (n = 0; n < ref->count; n++) { 10607f823a77SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 10617f823a77SEtienne Carriere continue; 10627f823a77SEtienne Carriere 10637f823a77SEtienne Carriere pc = ref->pinctrl + n; 10647f823a77SEtienne Carriere stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure); 10657f823a77SEtienne Carriere } 10667f823a77SEtienne Carriere } 10677f823a77SEtienne Carriere } 10687f823a77SEtienne Carriere 1069b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */ 1070b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs, 1071b38386fbSEtienne Carriere void *data __unused, 1072b38386fbSEtienne Carriere struct pinconf **out_pinconf) 1073b38386fbSEtienne Carriere { 1074b38386fbSEtienne Carriere struct conf { 1075b38386fbSEtienne Carriere struct pinconf pinconf; 1076b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref; 1077b38386fbSEtienne Carriere } *loc_conf = NULL; 1078b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL; 1079b38386fbSEtienne Carriere struct pinconf *pinconf = NULL; 1080b38386fbSEtienne Carriere const void *fdt = NULL; 1081b38386fbSEtienne Carriere size_t pin_count = 0; 1082b38386fbSEtienne Carriere int pinctrl_node = 0; 1083b38386fbSEtienne Carriere int pinmux_node = 0; 1084b38386fbSEtienne Carriere int count = 0; 1085b38386fbSEtienne Carriere 1086b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node; 1087b38386fbSEtienne Carriere fdt = pargs->fdt; 1088b38386fbSEtienne Carriere assert(fdt && pinctrl_node); 1089b38386fbSEtienne Carriere 1090b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 1091b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count)) 1092b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t); 1093b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND) 1094b38386fbSEtienne Carriere panic(); 1095b38386fbSEtienne Carriere } 1096b38386fbSEtienne Carriere 1097b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count); 1098b38386fbSEtienne Carriere if (!loc_conf) 1099b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 1100b38386fbSEtienne Carriere 1101b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf; 1102b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops; 1103b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref; 1104b38386fbSEtienne Carriere 1105b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count; 1106b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl; 1107b38386fbSEtienne Carriere 1108b38386fbSEtienne Carriere count = 0; 1109b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 1110b38386fbSEtienne Carriere int found = 0; 1111b38386fbSEtienne Carriere 1112b38386fbSEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count, 1113b38386fbSEtienne Carriere pin_count - count); 1114b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) { 1115b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */ 1116b38386fbSEtienne Carriere panic(); 1117b38386fbSEtienne Carriere } 1118b38386fbSEtienne Carriere 1119b38386fbSEtienne Carriere count += found; 1120b38386fbSEtienne Carriere } 1121b38386fbSEtienne Carriere 1122b38386fbSEtienne Carriere *out_pinconf = pinconf; 1123b38386fbSEtienne Carriere 1124b38386fbSEtienne Carriere return TEE_SUCCESS; 1125b38386fbSEtienne Carriere } 1126b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 1127b38386fbSEtienne Carriere 1128*bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank) 1129*bd03c8c3SGatien Chevallier { 1130*bd03c8c3SGatien Chevallier if (bank->sec_support) { 1131*bd03c8c3SGatien Chevallier clk_enable(bank->clock); 1132*bd03c8c3SGatien Chevallier io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr); 1133*bd03c8c3SGatien Chevallier clk_disable(bank->clock); 1134*bd03c8c3SGatien Chevallier } 1135*bd03c8c3SGatien Chevallier } 1136*bd03c8c3SGatien Chevallier 1137*bd03c8c3SGatien Chevallier /* 1138*bd03c8c3SGatien Chevallier * Several pinctrl nodes can be probed. Their bank will be put in the unique 1139*bd03c8c3SGatien Chevallier * bank_list. To avoid multiple configuration set for a bank when looping 1140*bd03c8c3SGatien Chevallier * over each bank in the bank list, ready is set to true when a bank is 1141*bd03c8c3SGatien Chevallier * configured. Therefore, during other bank probes, the configuration won't 1142*bd03c8c3SGatien Chevallier * be set again. 1143*bd03c8c3SGatien Chevallier */ 1144*bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void) 1145*bd03c8c3SGatien Chevallier { 1146*bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 1147*bd03c8c3SGatien Chevallier struct stm32_gpio_bank *bank = NULL; 1148*bd03c8c3SGatien Chevallier 1149*bd03c8c3SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) { 1150*bd03c8c3SGatien Chevallier if (bank->ready) 1151*bd03c8c3SGatien Chevallier continue; 1152*bd03c8c3SGatien Chevallier 1153*bd03c8c3SGatien Chevallier if (bank->rif_cfg) { 1154*bd03c8c3SGatien Chevallier res = apply_rif_config(bank); 1155*bd03c8c3SGatien Chevallier if (res) { 1156*bd03c8c3SGatien Chevallier EMSG("Failed to set GPIO bank %c RIF config", 1157*bd03c8c3SGatien Chevallier 'A' + bank->bank_id); 1158*bd03c8c3SGatien Chevallier STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank, 1159*bd03c8c3SGatien Chevallier link); 1160*bd03c8c3SGatien Chevallier return res; 1161*bd03c8c3SGatien Chevallier } 1162*bd03c8c3SGatien Chevallier } else { 1163*bd03c8c3SGatien Chevallier stm32_gpio_set_conf_sec(bank); 1164*bd03c8c3SGatien Chevallier } 1165*bd03c8c3SGatien Chevallier 1166*bd03c8c3SGatien Chevallier bank->ready = true; 1167*bd03c8c3SGatien Chevallier } 1168*bd03c8c3SGatien Chevallier 1169*bd03c8c3SGatien Chevallier return TEE_SUCCESS; 1170*bd03c8c3SGatien Chevallier } 1171*bd03c8c3SGatien Chevallier 11720e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 11730e0435e2SEtienne Carriere const void *compat_data) 11740e0435e2SEtienne Carriere { 1175b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 1176b38386fbSEtienne Carriere 11770e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 1178b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data); 1179b38386fbSEtienne Carriere if (res) 1180b38386fbSEtienne Carriere return res; 1181b38386fbSEtienne Carriere 1182*bd03c8c3SGatien Chevallier if (STAILQ_EMPTY(&bank_list)) 1183*bd03c8c3SGatien Chevallier DMSG("no gpio bank for that driver"); 1184*bd03c8c3SGatien Chevallier else if (apply_sec_cfg()) 1185*bd03c8c3SGatien Chevallier panic(); 1186*bd03c8c3SGatien Chevallier 1187b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 1188b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get, 1189b38386fbSEtienne Carriere (void *)compat_data); 1190b38386fbSEtienne Carriere if (res) 1191*bd03c8c3SGatien Chevallier panic(); 1192b38386fbSEtienne Carriere #endif 1193b38386fbSEtienne Carriere 1194b38386fbSEtienne Carriere return TEE_SUCCESS; 11950e0435e2SEtienne Carriere } 11960e0435e2SEtienne Carriere 11970e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 1198e569f6adSEtienne Carriere { 1199e569f6adSEtienne Carriere .compatible = "st,stm32mp135-pinctrl", 1200b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1201b4893304SGatien Chevallier .secure_control = true, 1202*bd03c8c3SGatien Chevallier .secure_extended = false, 1203b4893304SGatien Chevallier }, 1204e569f6adSEtienne Carriere }, 1205e569f6adSEtienne Carriere { 1206e569f6adSEtienne Carriere .compatible = "st,stm32mp157-pinctrl", 1207b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1208b4893304SGatien Chevallier .secure_control = false, 1209*bd03c8c3SGatien Chevallier .secure_extended = false, 1210b4893304SGatien Chevallier }, 1211e569f6adSEtienne Carriere }, 1212e569f6adSEtienne Carriere { 1213e569f6adSEtienne Carriere .compatible = "st,stm32mp157-z-pinctrl", 1214b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 1215b4893304SGatien Chevallier .gpioz = true, 1216b4893304SGatien Chevallier .secure_control = true, 1217*bd03c8c3SGatien Chevallier .secure_extended = false, 1218*bd03c8c3SGatien Chevallier }, 1219*bd03c8c3SGatien Chevallier }, 1220*bd03c8c3SGatien Chevallier { 1221*bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-pinctrl", 1222*bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){ 1223*bd03c8c3SGatien Chevallier .secure_control = true, 1224*bd03c8c3SGatien Chevallier .secure_extended = true, 1225*bd03c8c3SGatien Chevallier }, 1226*bd03c8c3SGatien Chevallier }, 1227*bd03c8c3SGatien Chevallier { 1228*bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-z-pinctrl", 1229*bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){ 1230*bd03c8c3SGatien Chevallier .gpioz = true, 1231*bd03c8c3SGatien Chevallier .secure_control = true, 1232*bd03c8c3SGatien Chevallier .secure_extended = true, 1233b4893304SGatien Chevallier }, 1234e569f6adSEtienne Carriere }, 12350e0435e2SEtienne Carriere { } 12360e0435e2SEtienne Carriere }; 12370e0435e2SEtienne Carriere 12380e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 12390e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 12400e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 12410e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 12420e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 12430e0435e2SEtienne Carriere }; 1244