14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 24b5e93edSEtienne Carriere /* 39818a481SEtienne Carriere * Copyright (c) 2017-2023, STMicroelectronics 44b5e93edSEtienne Carriere * 54b5e93edSEtienne Carriere * STM32 GPIO driver is used as pin controller for stm32mp SoCs. 64b5e93edSEtienne Carriere */ 74b5e93edSEtienne Carriere 84b5e93edSEtienne Carriere #include <assert.h> 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*b4893304SGatien Chevallier #include <dt-bindings/gpio/stm32mp_gpio.h> 164b5e93edSEtienne Carriere #include <io.h> 174b5e93edSEtienne Carriere #include <kernel/dt.h> 1865401337SJens Wiklander #include <kernel/boot.h> 194b5e93edSEtienne Carriere #include <kernel/panic.h> 204b5e93edSEtienne Carriere #include <kernel/spinlock.h> 21a2fc83d1SJerome Forissier #include <libfdt.h> 224b5e93edSEtienne Carriere #include <mm/core_memprot.h> 234b5e93edSEtienne Carriere #include <stdbool.h> 2469715ce9SEtienne Carriere #include <stdint.h> 254b5e93edSEtienne Carriere #include <stm32_util.h> 269818a481SEtienne Carriere #include <sys/queue.h> 274b5e93edSEtienne Carriere #include <trace.h> 284b5e93edSEtienne Carriere #include <util.h> 294b5e93edSEtienne Carriere 301001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 311001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 321001585eSEtienne Carriere #endif 331001585eSEtienne Carriere 344b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 354b5e93edSEtienne Carriere 365eed568cSGatien Chevallier #define GPIO_MODER_OFFSET U(0x00) 375eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET U(0x04) 385eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET U(0x08) 395eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET U(0x0c) 405eed568cSGatien Chevallier #define GPIO_IDR_OFFSET U(0x10) 415eed568cSGatien Chevallier #define GPIO_ODR_OFFSET U(0x14) 425eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET U(0x18) 435eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET U(0x20) 445eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET U(0x24) 455eed568cSGatien Chevallier #define GPIO_SECR_OFFSET U(0x30) 464b5e93edSEtienne Carriere 475eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT U(0x8) 484b5e93edSEtienne Carriere 494b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 504b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 514b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 52729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 534b5e93edSEtienne Carriere 545eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT U(12) 554b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 565eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT U(8) 574b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 584b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 594b5e93edSEtienne Carriere 609818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 619818a481SEtienne Carriere 6269715ce9SEtienne Carriere #define GPIO_MODE_INPUT U(0x0) 6369715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT U(0x1) 6469715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE U(0x2) 6569715ce9SEtienne Carriere #define GPIO_MODE_ANALOG U(0x3) 6669715ce9SEtienne Carriere 6769715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL U(0x0) 6869715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN U(0x1) 6969715ce9SEtienne Carriere 7069715ce9SEtienne Carriere #define GPIO_OSPEED_LOW U(0x0) 7169715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM U(0x1) 7269715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH U(0x2) 7369715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH U(0x3) 7469715ce9SEtienne Carriere 7569715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL U(0x0) 7669715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP U(0x1) 7769715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN U(0x2) 7869715ce9SEtienne Carriere 7969715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW U(0x0) 8069715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH U(0x1) 8169715ce9SEtienne Carriere 8269715ce9SEtienne Carriere /* 8369715ce9SEtienne Carriere * GPIO configuration description structured as single 16bit word 8469715ce9SEtienne Carriere * for efficient save/restore when GPIO pin suspends or resumes. 8569715ce9SEtienne Carriere * 8669715ce9SEtienne Carriere * @mode: One of GPIO_MODE_* 8769715ce9SEtienne Carriere * @otype: One of GPIO_OTYPE_* 8869715ce9SEtienne Carriere * @ospeed: One of GPIO_OSPEED_* 8969715ce9SEtienne Carriere * @pupd: One of GPIO_PUPD_* 9069715ce9SEtienne Carriere * @od: One of GPIO_OD_* 9169715ce9SEtienne Carriere * @af: Alternate function numerical ID between 0 and 15 9269715ce9SEtienne Carriere */ 9369715ce9SEtienne Carriere struct gpio_cfg { 9469715ce9SEtienne Carriere uint16_t mode: 2; 9569715ce9SEtienne Carriere uint16_t otype: 1; 9669715ce9SEtienne Carriere uint16_t ospeed: 2; 9769715ce9SEtienne Carriere uint16_t pupd: 2; 9869715ce9SEtienne Carriere uint16_t od: 1; 9969715ce9SEtienne Carriere uint16_t af: 4; 10069715ce9SEtienne Carriere }; 10169715ce9SEtienne Carriere 10269715ce9SEtienne Carriere /* 10369715ce9SEtienne Carriere * Description of a pin and its muxing 10469715ce9SEtienne Carriere * 10569715ce9SEtienne Carriere * @bank: GPIO bank identifier as assigned by the platform 10669715ce9SEtienne Carriere * @pin: Pin number in the GPIO bank 10769715ce9SEtienne Carriere * @cfg: Pin configuration 10869715ce9SEtienne Carriere */ 10969715ce9SEtienne Carriere struct stm32_pinctrl { 11069715ce9SEtienne Carriere uint8_t bank; 11169715ce9SEtienne Carriere uint8_t pin; 11269715ce9SEtienne Carriere struct gpio_cfg cfg; 11369715ce9SEtienne Carriere }; 11469715ce9SEtienne Carriere 115b38386fbSEtienne Carriere /* 116b38386fbSEtienne Carriere * struct stm32_pinctrl_array - Array of pins in a pin control state 117b38386fbSEtienne Carriere * @count: Number of cells in @pinctrl 118b38386fbSEtienne Carriere * @pinctrl: Pin control configuration 119b38386fbSEtienne Carriere */ 120b38386fbSEtienne Carriere struct stm32_pinctrl_array { 121b38386fbSEtienne Carriere size_t count; 122b38386fbSEtienne Carriere struct stm32_pinctrl pinctrl[]; 123b38386fbSEtienne Carriere }; 124b38386fbSEtienne Carriere 1259818a481SEtienne Carriere /** 1269818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 1279818a481SEtienne Carriere * 1289818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 1299818a481SEtienne Carriere * @clock: clock identifier. 130420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 1319818a481SEtienne Carriere * @ngpios: number of GPIOs. 1329818a481SEtienne Carriere * @bank_id: Id of the bank. 1339818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 1349818a481SEtienne Carriere * @sec_support: True if bank supports pin security protection, otherwise false 1359818a481SEtienne Carriere * @link: Link in bank list 1369818a481SEtienne Carriere */ 1379818a481SEtienne Carriere struct stm32_gpio_bank { 1389818a481SEtienne Carriere vaddr_t base; 1399818a481SEtienne Carriere struct clk *clock; 140420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 1419818a481SEtienne Carriere unsigned int ngpios; 1429818a481SEtienne Carriere unsigned int bank_id; 1439818a481SEtienne Carriere unsigned int lock; 144*b4893304SGatien Chevallier bool sec_support; 1459818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 1469818a481SEtienne Carriere }; 1479818a481SEtienne Carriere 148*b4893304SGatien Chevallier /** 149e569f6adSEtienne Carriere * Compatibility information of supported banks 150*b4893304SGatien Chevallier * 151*b4893304SGatien Chevallier * @gpioz: True if bank is a GPIOZ bank 152*b4893304SGatien Chevallier * @secure_control: Identify GPIO security bank capability. 153e569f6adSEtienne Carriere */ 154e569f6adSEtienne Carriere struct bank_compat { 155e569f6adSEtienne Carriere bool gpioz; 156*b4893304SGatien Chevallier bool secure_control; 157e569f6adSEtienne Carriere }; 158e569f6adSEtienne Carriere 1594b5e93edSEtienne Carriere static unsigned int gpio_lock; 1604b5e93edSEtienne Carriere 1619818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 1629818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 1639818a481SEtienne Carriere 164420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 165420a32c5SEtienne Carriere 166420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 167420a32c5SEtienne Carriere { 168420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 169420a32c5SEtienne Carriere } 170420a32c5SEtienne Carriere 171420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 172420a32c5SEtienne Carriere unsigned int gpio_pin) 173420a32c5SEtienne Carriere { 174420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 175420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 176420a32c5SEtienne Carriere unsigned int reg_offset = 0; 177420a32c5SEtienne Carriere unsigned int mode = 0; 178420a32c5SEtienne Carriere 179420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1802fd102ebSEtienne Carriere 1812fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1822fd102ebSEtienne Carriere panic(); 183420a32c5SEtienne Carriere 184420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 185420a32c5SEtienne Carriere GPIO_MODE_MASK; 186420a32c5SEtienne Carriere 187420a32c5SEtienne Carriere switch (mode) { 188420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 189420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 190420a32c5SEtienne Carriere break; 191420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 192420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 193420a32c5SEtienne Carriere break; 194420a32c5SEtienne Carriere default: 195420a32c5SEtienne Carriere panic(); 196420a32c5SEtienne Carriere } 197420a32c5SEtienne Carriere 198420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 199420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 200420a32c5SEtienne Carriere else 201420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 202420a32c5SEtienne Carriere 203420a32c5SEtienne Carriere clk_disable(bank->clock); 204420a32c5SEtienne Carriere 205420a32c5SEtienne Carriere return level; 206420a32c5SEtienne Carriere } 207420a32c5SEtienne Carriere 208420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 209420a32c5SEtienne Carriere enum gpio_level level) 210420a32c5SEtienne Carriere { 211420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 212420a32c5SEtienne Carriere 213420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2142fd102ebSEtienne Carriere 2152fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2162fd102ebSEtienne Carriere panic(); 217420a32c5SEtienne Carriere 218420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 219420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 220420a32c5SEtienne Carriere 221420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 222420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 223420a32c5SEtienne Carriere else 224420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 225420a32c5SEtienne Carriere 226420a32c5SEtienne Carriere clk_disable(bank->clock); 227420a32c5SEtienne Carriere } 228420a32c5SEtienne Carriere 229420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 230420a32c5SEtienne Carriere unsigned int gpio_pin) 231420a32c5SEtienne Carriere { 232420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 233420a32c5SEtienne Carriere uint32_t mode = 0; 234420a32c5SEtienne Carriere 235420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2362fd102ebSEtienne Carriere 2372fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2382fd102ebSEtienne Carriere panic(); 239420a32c5SEtienne Carriere 240420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 241420a32c5SEtienne Carriere GPIO_MODE_MASK; 242420a32c5SEtienne Carriere 243420a32c5SEtienne Carriere clk_disable(bank->clock); 244420a32c5SEtienne Carriere 245420a32c5SEtienne Carriere switch (mode) { 246420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 247420a32c5SEtienne Carriere return GPIO_DIR_IN; 248420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 249420a32c5SEtienne Carriere return GPIO_DIR_OUT; 250420a32c5SEtienne Carriere default: 251420a32c5SEtienne Carriere panic(); 252420a32c5SEtienne Carriere } 253420a32c5SEtienne Carriere } 254420a32c5SEtienne Carriere 255420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 256420a32c5SEtienne Carriere unsigned int gpio_pin, 257420a32c5SEtienne Carriere enum gpio_dir direction) 258420a32c5SEtienne Carriere { 259420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 260420a32c5SEtienne Carriere uint32_t exceptions = 0; 261420a32c5SEtienne Carriere uint32_t mode = 0; 262420a32c5SEtienne Carriere 263420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 264420a32c5SEtienne Carriere 265420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 266420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 267420a32c5SEtienne Carriere else 268420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 269420a32c5SEtienne Carriere 2702fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2712fd102ebSEtienne Carriere panic(); 272420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 273420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 274420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 275420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 276420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 277420a32c5SEtienne Carriere clk_disable(bank->clock); 278420a32c5SEtienne Carriere } 279420a32c5SEtienne Carriere 280420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 281420a32c5SEtienne Carriere struct gpio *gpio) 282420a32c5SEtienne Carriere { 283420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 284420a32c5SEtienne Carriere free(gpio); 285420a32c5SEtienne Carriere } 286420a32c5SEtienne Carriere 287420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 288420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 289420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 290420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 291420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 292420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 293420a32c5SEtienne Carriere }; 294420a32c5SEtienne Carriere 295420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 296420a32c5SEtienne Carriere { 297420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 298420a32c5SEtienne Carriere } 299420a32c5SEtienne Carriere 300077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 3014b5e93edSEtienne Carriere { 302077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 3034b5e93edSEtienne Carriere 304077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 305077d486eSEtienne Carriere if (bank_id == bank->bank_id) 306077d486eSEtienne Carriere return bank; 307077d486eSEtienne Carriere 308077d486eSEtienne Carriere panic(); 309077d486eSEtienne Carriere } 310077d486eSEtienne Carriere 311077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 312b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin, 313b38386fbSEtienne Carriere struct gpio_cfg *cfg) 314077d486eSEtienne Carriere { 315077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 316077d486eSEtienne Carriere 317077d486eSEtienne Carriere if (clk_enable(bank->clock)) 318077d486eSEtienne Carriere panic(); 3194b5e93edSEtienne Carriere 3204b5e93edSEtienne Carriere /* 3214b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 3224b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 3234b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 3244b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 3254b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 3264b5e93edSEtienne Carriere */ 327077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 3284b5e93edSEtienne Carriere GPIO_MODE_MASK; 3294b5e93edSEtienne Carriere 330077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 3314b5e93edSEtienne Carriere 332077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 333077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 3344b5e93edSEtienne Carriere 335077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 3364b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 3374b5e93edSEtienne Carriere 338077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 3394b5e93edSEtienne Carriere 3404b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 341077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 342077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 3434b5e93edSEtienne Carriere else 344077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 3454b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 3464b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 3474b5e93edSEtienne Carriere 348077d486eSEtienne Carriere clk_disable(bank->clock); 3494b5e93edSEtienne Carriere } 3504b5e93edSEtienne Carriere 3514b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 352077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 3534b5e93edSEtienne Carriere { 354077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 35598dfcedaSEtienne Carriere uint32_t exceptions = 0; 3564b5e93edSEtienne Carriere 357077d486eSEtienne Carriere if (clk_enable(bank->clock)) 358077d486eSEtienne Carriere panic(); 35998dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 3604b5e93edSEtienne Carriere 3614b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 362077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 363bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 364bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 3654b5e93edSEtienne Carriere 3664b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 367077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 368bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 3694b5e93edSEtienne Carriere 3704b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 371077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 372bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 373bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 3744b5e93edSEtienne Carriere 3754b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 376077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 377bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 3784b5e93edSEtienne Carriere 3794b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 3804b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 381077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 382bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 383bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 3844b5e93edSEtienne Carriere } else { 3854b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 3864b5e93edSEtienne Carriere 387077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 388bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 389bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 3904b5e93edSEtienne Carriere } 3914b5e93edSEtienne Carriere 3924b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 393077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 3944b5e93edSEtienne Carriere 395c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 39698dfcedaSEtienne Carriere clk_disable(bank->clock); 3974b5e93edSEtienne Carriere } 3984b5e93edSEtienne Carriere 3994b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 400b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node, 4014b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 4024b5e93edSEtienne Carriere { 403b38386fbSEtienne Carriere const fdt32_t *cuint = NULL; 404b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL; 40510bcbd6cSEtienne Carriere int len = 0; 40610bcbd6cSEtienne Carriere uint32_t i = 0; 4074b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 4084b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 4094b5e93edSEtienne Carriere size_t found = 0; 4104b5e93edSEtienne Carriere 4114b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 4124b5e93edSEtienne Carriere if (!cuint) 4134b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 4144b5e93edSEtienne Carriere 4154b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 4164b5e93edSEtienne Carriere if (slewrate) 4174b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 4184b5e93edSEtienne Carriere 4194b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 4204b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 4214b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 4224b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 4234b5e93edSEtienne Carriere 4244b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 42510bcbd6cSEtienne Carriere uint32_t pincfg = 0; 42610bcbd6cSEtienne Carriere uint32_t bank = 0; 42710bcbd6cSEtienne Carriere uint32_t pin = 0; 42810bcbd6cSEtienne Carriere uint32_t mode = 0; 4294b5e93edSEtienne Carriere uint32_t alternate = 0; 430322cf9e3SEtienne Carriere uint32_t odata = 0; 4314b5e93edSEtienne Carriere bool opendrain = false; 4324b5e93edSEtienne Carriere 4334b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 4344b5e93edSEtienne Carriere cuint++; 4354b5e93edSEtienne Carriere 4364b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 4374b5e93edSEtienne Carriere 4384b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 4394b5e93edSEtienne Carriere 4404b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 4414b5e93edSEtienne Carriere 4424b5e93edSEtienne Carriere switch (mode) { 4434b5e93edSEtienne Carriere case 0: 4444b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 4454b5e93edSEtienne Carriere break; 4464b5e93edSEtienne Carriere case 1: 4474b5e93edSEtienne Carriere case 2: 4484b5e93edSEtienne Carriere case 3: 4494b5e93edSEtienne Carriere case 4: 4504b5e93edSEtienne Carriere case 5: 4514b5e93edSEtienne Carriere case 6: 4524b5e93edSEtienne Carriere case 7: 4534b5e93edSEtienne Carriere case 8: 4544b5e93edSEtienne Carriere case 9: 4554b5e93edSEtienne Carriere case 10: 4564b5e93edSEtienne Carriere case 11: 4574b5e93edSEtienne Carriere case 12: 4584b5e93edSEtienne Carriere case 13: 4594b5e93edSEtienne Carriere case 14: 4604b5e93edSEtienne Carriere case 15: 4614b5e93edSEtienne Carriere case 16: 4624b5e93edSEtienne Carriere alternate = mode - 1U; 4634b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 4644b5e93edSEtienne Carriere break; 4654b5e93edSEtienne Carriere case 17: 4664b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 4674b5e93edSEtienne Carriere break; 4684b5e93edSEtienne Carriere default: 4694b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 4704b5e93edSEtienne Carriere break; 4714b5e93edSEtienne Carriere } 4724b5e93edSEtienne Carriere 4734b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 4744b5e93edSEtienne Carriere opendrain = true; 4754b5e93edSEtienne Carriere 476322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 477322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 478322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 479322cf9e3SEtienne Carriere odata = 1; 480322cf9e3SEtienne Carriere } 481322cf9e3SEtienne Carriere 482322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 483322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 484322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 485322cf9e3SEtienne Carriere odata = 0; 486322cf9e3SEtienne Carriere } 487322cf9e3SEtienne Carriere 4884b5e93edSEtienne Carriere if (found < count) { 4894b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 4904b5e93edSEtienne Carriere 4914b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 4924b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 493b38386fbSEtienne Carriere ref->cfg.mode = mode; 494b38386fbSEtienne Carriere if (opendrain) 495b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN; 496b38386fbSEtienne Carriere else 497b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL; 498b38386fbSEtienne Carriere ref->cfg.ospeed = speed; 499b38386fbSEtienne Carriere ref->cfg.pupd = pull; 500b38386fbSEtienne Carriere ref->cfg.od = odata; 501b38386fbSEtienne Carriere ref->cfg.af = alternate; 5024b5e93edSEtienne Carriere } 5034b5e93edSEtienne Carriere 5044b5e93edSEtienne Carriere found++; 5054b5e93edSEtienne Carriere } 5064b5e93edSEtienne Carriere 5074b5e93edSEtienne Carriere return (int)found; 5084b5e93edSEtienne Carriere } 5094b5e93edSEtienne Carriere 510b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data, 511b357d34fSEtienne Carriere struct gpio **out_gpio) 512420a32c5SEtienne Carriere { 513b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 514420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 515420a32c5SEtienne Carriere struct gpio *gpio = NULL; 516420a32c5SEtienne Carriere unsigned int shift_1b = 0; 517420a32c5SEtienne Carriere unsigned int shift_2b = 0; 518420a32c5SEtienne Carriere uint32_t exceptions = 0; 519420a32c5SEtienne Carriere uint32_t otype = 0; 520420a32c5SEtienne Carriere uint32_t pupd = 0; 521420a32c5SEtienne Carriere uint32_t mode = 0; 522420a32c5SEtienne Carriere 523b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio); 524b357d34fSEtienne Carriere if (res) 525b357d34fSEtienne Carriere return res; 526420a32c5SEtienne Carriere 527420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 528420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 529420a32c5SEtienne Carriere free(gpio); 530b357d34fSEtienne Carriere return TEE_ERROR_GENERIC; 531420a32c5SEtienne Carriere } 532420a32c5SEtienne Carriere 533420a32c5SEtienne Carriere shift_1b = gpio->pin; 534420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 535420a32c5SEtienne Carriere 536420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 537420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 538420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 539420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 540420a32c5SEtienne Carriere else 541420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 542420a32c5SEtienne Carriere 543420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 544420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 545420a32c5SEtienne Carriere else 546420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 547420a32c5SEtienne Carriere 548420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 549420a32c5SEtienne Carriere panic(); 550420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 551420a32c5SEtienne Carriere 552420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 553420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 554420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 555420a32c5SEtienne Carriere 556420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 557420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 558420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 559420a32c5SEtienne Carriere 560420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 561420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 562420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 563420a32c5SEtienne Carriere 564420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 565420a32c5SEtienne Carriere clk_disable(bank->clock); 566420a32c5SEtienne Carriere 567420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 568420a32c5SEtienne Carriere 569b357d34fSEtienne Carriere *out_gpio = gpio; 570420a32c5SEtienne Carriere 571b357d34fSEtienne Carriere return TEE_SUCCESS; 572420a32c5SEtienne Carriere } 573420a32c5SEtienne Carriere 5749818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 5759818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 5769818a481SEtienne Carriere { 5779818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 5789818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5799818a481SEtienne Carriere int len = 0; 5809818a481SEtienne Carriere 5819818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 5829818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 5839818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 5849818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 5859818a481SEtienne Carriere 5869818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 5879818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 5889818a481SEtienne Carriere panic("Wrong st,bank-name property"); 5899818a481SEtienne Carriere 5909818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 5919818a481SEtienne Carriere } 5929818a481SEtienne Carriere 5939818a481SEtienne Carriere /* 5949818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 5959818a481SEtienne Carriere * registered in the GPIO bank link. 5969818a481SEtienne Carriere */ 5979818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 5989818a481SEtienne Carriere { 5999818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 6009818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6019818a481SEtienne Carriere 6029818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 6039818a481SEtienne Carriere if (bank->bank_id == bank_id) 6049818a481SEtienne Carriere return true; 6059818a481SEtienne Carriere 6069818a481SEtienne Carriere return false; 6079818a481SEtienne Carriere } 6089818a481SEtienne Carriere 6099818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 6109818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 611e569f6adSEtienne Carriere const void *compat_data, 6129818a481SEtienne Carriere int range_offset, 6139818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 6149818a481SEtienne Carriere { 615e569f6adSEtienne Carriere const struct bank_compat *compat = compat_data; 6169818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 6179818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6189818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6199818a481SEtienne Carriere struct io_pa_va pa_va = { }; 6209818a481SEtienne Carriere struct clk *clk = NULL; 6219818a481SEtienne Carriere size_t blen = 0; 6229818a481SEtienne Carriere paddr_t pa = 0; 6239818a481SEtienne Carriere int len = 0; 6249818a481SEtienne Carriere int i = 0; 6259818a481SEtienne Carriere 6269818a481SEtienne Carriere assert(out_bank); 6279818a481SEtienne Carriere 6289818a481SEtienne Carriere /* Probe deferrable devices first */ 6299818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 6309818a481SEtienne Carriere if (res) 6319818a481SEtienne Carriere return res; 6329818a481SEtienne Carriere 6339818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 6349818a481SEtienne Carriere if (!bank) 6359818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 6369818a481SEtienne Carriere 6379818a481SEtienne Carriere /* 6389818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 6399818a481SEtienne Carriere * but consider also the "ranges" translation property 6409818a481SEtienne Carriere */ 6419818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 6429818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 6439818a481SEtienne Carriere panic("missing reg property"); 6449818a481SEtienne Carriere 6459818a481SEtienne Carriere pa_va.pa = pa + range_offset; 6469818a481SEtienne Carriere 6479818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 6489818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 6499818a481SEtienne Carriere panic("missing reg size property"); 6509818a481SEtienne Carriere 6519818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 6529818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 6539818a481SEtienne Carriere bank->clock = clk; 654420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 655*b4893304SGatien Chevallier bank->sec_support = compat->secure_control; 656*b4893304SGatien Chevallier if (bank->sec_support) 657*b4893304SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen); 658*b4893304SGatien Chevallier else 659*b4893304SGatien Chevallier bank->base = io_pa_or_va_nsec(&pa_va, blen); 660*b4893304SGatien Chevallier assert(bank->base); 6619818a481SEtienne Carriere 6629818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 6639818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 6649818a481SEtienne Carriere len /= sizeof(*cuint); 6659818a481SEtienne Carriere if (len % 4) 6669818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 6679818a481SEtienne Carriere 6689818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 6699818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 6709818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 6719818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 6729818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 6739818a481SEtienne Carriere cuint += 4; 6749818a481SEtienne Carriere } 6759818a481SEtienne Carriere 676e569f6adSEtienne Carriere if (compat->gpioz) 677e569f6adSEtienne Carriere stm32mp_register_gpioz_pin_count(bank->ngpios); 678e569f6adSEtienne Carriere 6799818a481SEtienne Carriere *out_bank = bank; 6809818a481SEtienne Carriere return TEE_SUCCESS; 6819818a481SEtienne Carriere } 6829818a481SEtienne Carriere 683be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank) 684be53ee7bSEtienne Carriere { 685be53ee7bSEtienne Carriere unsigned int pin = 0; 686be53ee7bSEtienne Carriere 687580e08cfSGatien Chevallier for (pin = 0; pin < bank->ngpios; pin++) 688be53ee7bSEtienne Carriere stm32_gpio_set_secure_cfg(bank->bank_id, pin, false); 689be53ee7bSEtienne Carriere } 690be53ee7bSEtienne Carriere 691*b4893304SGatien Chevallier /* Parse a pinctrl node to register and configure the GPIO banks it describes */ 6920e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 6939818a481SEtienne Carriere const void *compat_data) 6949818a481SEtienne Carriere { 6959818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 6969818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6979818a481SEtienne Carriere int range_offs = 0; 6989818a481SEtienne Carriere int b_node = 0; 6999818a481SEtienne Carriere int len = 0; 7009818a481SEtienne Carriere 7019818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 7029818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 7039818a481SEtienne Carriere if (!cuint) 7049818a481SEtienne Carriere panic("missing ranges property"); 7059818a481SEtienne Carriere 7069818a481SEtienne Carriere len /= sizeof(*cuint); 7079818a481SEtienne Carriere if (len == 3) 7089818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 7099818a481SEtienne Carriere 7109818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 7119818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 7129818a481SEtienne Carriere if (cuint) { 7139818a481SEtienne Carriere /* 7149818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 7159818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 7169818a481SEtienne Carriere * bank list. 7179818a481SEtienne Carriere */ 7189818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 7199818a481SEtienne Carriere 7209818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 7219818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 7229818a481SEtienne Carriere continue; 7239818a481SEtienne Carriere 7249818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 7259818a481SEtienne Carriere range_offs, &bank); 7269818a481SEtienne Carriere if (res) 7279818a481SEtienne Carriere return res; 7289818a481SEtienne Carriere 729420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 730420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 731420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 732420a32c5SEtienne Carriere if (res) 733420a32c5SEtienne Carriere panic(); 734420a32c5SEtienne Carriere 7359818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 736be53ee7bSEtienne Carriere 737*b4893304SGatien Chevallier DMSG("Registered GPIO bank %c (%d pins) @%#"PRIxVA, 738*b4893304SGatien Chevallier bank->bank_id + 'A', bank->ngpios, bank->base); 739*b4893304SGatien Chevallier 740*b4893304SGatien Chevallier assert(bank->ngpios <= GPIO_PIN_MAX + 1); 741*b4893304SGatien Chevallier 742*b4893304SGatien Chevallier if (bank->sec_support) { 743*b4893304SGatien Chevallier uint32_t seccfgr = 0; 744*b4893304SGatien Chevallier unsigned int i = 0; 745*b4893304SGatien Chevallier int lenp = 0; 746*b4893304SGatien Chevallier 747*b4893304SGatien Chevallier cuint = fdt_getprop(fdt, b_node, "st,protreg", 748*b4893304SGatien Chevallier &lenp); 749*b4893304SGatien Chevallier if (!cuint) { 750be53ee7bSEtienne Carriere set_bank_gpio_non_secure(bank); 751*b4893304SGatien Chevallier continue; 752*b4893304SGatien Chevallier } 753*b4893304SGatien Chevallier 754*b4893304SGatien Chevallier seccfgr = fdt32_to_cpu(*cuint); 755*b4893304SGatien Chevallier for (i = 0; i < bank->ngpios; i++) 756*b4893304SGatien Chevallier stm32_gpio_set_secure_cfg(bank->bank_id, 757*b4893304SGatien Chevallier i, 758*b4893304SGatien Chevallier seccfgr & 759*b4893304SGatien Chevallier TZPROT(i)); 760*b4893304SGatien Chevallier } 7619818a481SEtienne Carriere } else { 7629818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 7639818a481SEtienne Carriere panic(); 7649818a481SEtienne Carriere } 7659818a481SEtienne Carriere } 7669818a481SEtienne Carriere 7679818a481SEtienne Carriere return TEE_SUCCESS; 7689818a481SEtienne Carriere } 7699818a481SEtienne Carriere 770077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 771077d486eSEtienne Carriere bool secure) 7724b5e93edSEtienne Carriere { 773077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 77498dfcedaSEtienne Carriere uint32_t exceptions = 0; 7754b5e93edSEtienne Carriere 776077d486eSEtienne Carriere if (clk_enable(bank->clock)) 777077d486eSEtienne Carriere panic(); 77898dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 7794b5e93edSEtienne Carriere 7804b5e93edSEtienne Carriere if (secure) 781077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7824b5e93edSEtienne Carriere else 783077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7844b5e93edSEtienne Carriere 785*b4893304SGatien Chevallier FMSG("Set secure GPIO: bank %c pin %u", bank->bank_id + 'A', pin); 786*b4893304SGatien Chevallier 787c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 78898dfcedaSEtienne Carriere clk_disable(bank->clock); 7894b5e93edSEtienne Carriere } 7900e0435e2SEtienne Carriere 791b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 792b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf) 793b38386fbSEtienne Carriere { 794b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv; 795b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl; 796b38386fbSEtienne Carriere size_t pin_count = ref->count; 797b38386fbSEtienne Carriere size_t n = 0; 798b38386fbSEtienne Carriere 799b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++) 800b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg); 801b38386fbSEtienne Carriere 802b38386fbSEtienne Carriere return TEE_SUCCESS; 803b38386fbSEtienne Carriere } 804b38386fbSEtienne Carriere 805b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf) 806b38386fbSEtienne Carriere { 807b38386fbSEtienne Carriere free(conf); 808b38386fbSEtienne Carriere } 809b38386fbSEtienne Carriere 810b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = { 811b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply, 812b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free, 813b38386fbSEtienne Carriere }; 814b38386fbSEtienne Carriere 815b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops); 816b38386fbSEtienne Carriere 81770ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl, 81870ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin, 81970ac0db5SEtienne Carriere unsigned int *count) 82070ac0db5SEtienne Carriere { 82170ac0db5SEtienne Carriere size_t conf_index = 0; 82270ac0db5SEtienne Carriere size_t pin_count = 0; 82370ac0db5SEtienne Carriere size_t n = 0; 82470ac0db5SEtienne Carriere 82570ac0db5SEtienne Carriere assert(count); 82670ac0db5SEtienne Carriere if (!pinctrl) 82770ac0db5SEtienne Carriere goto out; 82870ac0db5SEtienne Carriere 82970ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 83070ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 83170ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 83270ac0db5SEtienne Carriere 83370ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */ 83470ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 83570ac0db5SEtienne Carriere continue; 83670ac0db5SEtienne Carriere 83770ac0db5SEtienne Carriere if (bank || pin) { 83870ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) { 83970ac0db5SEtienne Carriere if (bank && pin_count < *count) 84070ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank; 84170ac0db5SEtienne Carriere if (pin && pin_count < *count) 84270ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin; 84370ac0db5SEtienne Carriere pin_count++; 84470ac0db5SEtienne Carriere } 84570ac0db5SEtienne Carriere } else { 84670ac0db5SEtienne Carriere pin_count += ref->count; 84770ac0db5SEtienne Carriere } 84870ac0db5SEtienne Carriere } 84970ac0db5SEtienne Carriere 85070ac0db5SEtienne Carriere out: 85170ac0db5SEtienne Carriere *count = pin_count; 85270ac0db5SEtienne Carriere } 85370ac0db5SEtienne Carriere 8547f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure) 8557f823a77SEtienne Carriere { 8567f823a77SEtienne Carriere size_t conf_index = 0; 8577f823a77SEtienne Carriere 8587f823a77SEtienne Carriere if (!pinctrl) 8597f823a77SEtienne Carriere return; 8607f823a77SEtienne Carriere 8617f823a77SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 8627f823a77SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 8637f823a77SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 8647f823a77SEtienne Carriere struct stm32_pinctrl *pc = NULL; 8657f823a77SEtienne Carriere size_t n = 0; 8667f823a77SEtienne Carriere 8677f823a77SEtienne Carriere for (n = 0; n < ref->count; n++) { 8687f823a77SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 8697f823a77SEtienne Carriere continue; 8707f823a77SEtienne Carriere 8717f823a77SEtienne Carriere pc = ref->pinctrl + n; 8727f823a77SEtienne Carriere stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure); 8737f823a77SEtienne Carriere } 8747f823a77SEtienne Carriere } 8757f823a77SEtienne Carriere } 8767f823a77SEtienne Carriere 877b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */ 878b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs, 879b38386fbSEtienne Carriere void *data __unused, 880b38386fbSEtienne Carriere struct pinconf **out_pinconf) 881b38386fbSEtienne Carriere { 882b38386fbSEtienne Carriere struct conf { 883b38386fbSEtienne Carriere struct pinconf pinconf; 884b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref; 885b38386fbSEtienne Carriere } *loc_conf = NULL; 886b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL; 887b38386fbSEtienne Carriere struct pinconf *pinconf = NULL; 888b38386fbSEtienne Carriere const void *fdt = NULL; 889b38386fbSEtienne Carriere size_t pin_count = 0; 890b38386fbSEtienne Carriere int pinctrl_node = 0; 891b38386fbSEtienne Carriere int pinmux_node = 0; 892b38386fbSEtienne Carriere int count = 0; 893b38386fbSEtienne Carriere 894b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node; 895b38386fbSEtienne Carriere fdt = pargs->fdt; 896b38386fbSEtienne Carriere assert(fdt && pinctrl_node); 897b38386fbSEtienne Carriere 898b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 899b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count)) 900b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t); 901b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND) 902b38386fbSEtienne Carriere panic(); 903b38386fbSEtienne Carriere } 904b38386fbSEtienne Carriere 905b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count); 906b38386fbSEtienne Carriere if (!loc_conf) 907b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 908b38386fbSEtienne Carriere 909b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf; 910b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops; 911b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref; 912b38386fbSEtienne Carriere 913b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count; 914b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl; 915b38386fbSEtienne Carriere 916b38386fbSEtienne Carriere count = 0; 917b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 918b38386fbSEtienne Carriere int found = 0; 919b38386fbSEtienne Carriere 920b38386fbSEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count, 921b38386fbSEtienne Carriere pin_count - count); 922b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) { 923b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */ 924b38386fbSEtienne Carriere panic(); 925b38386fbSEtienne Carriere } 926b38386fbSEtienne Carriere 927b38386fbSEtienne Carriere count += found; 928b38386fbSEtienne Carriere } 929b38386fbSEtienne Carriere 930b38386fbSEtienne Carriere *out_pinconf = pinconf; 931b38386fbSEtienne Carriere 932b38386fbSEtienne Carriere return TEE_SUCCESS; 933b38386fbSEtienne Carriere } 934b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 935b38386fbSEtienne Carriere 9360e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 9370e0435e2SEtienne Carriere const void *compat_data) 9380e0435e2SEtienne Carriere { 939b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 940b38386fbSEtienne Carriere 9410e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 942b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data); 943b38386fbSEtienne Carriere if (res) 944b38386fbSEtienne Carriere return res; 945b38386fbSEtienne Carriere 946b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 947b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get, 948b38386fbSEtienne Carriere (void *)compat_data); 949b38386fbSEtienne Carriere if (res) 950b38386fbSEtienne Carriere return res; 951b38386fbSEtienne Carriere #endif 952b38386fbSEtienne Carriere 953b38386fbSEtienne Carriere return TEE_SUCCESS; 9540e0435e2SEtienne Carriere } 9550e0435e2SEtienne Carriere 9560e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 957e569f6adSEtienne Carriere { 958e569f6adSEtienne Carriere .compatible = "st,stm32mp135-pinctrl", 959*b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 960*b4893304SGatien Chevallier .secure_control = true, 961*b4893304SGatien Chevallier }, 962e569f6adSEtienne Carriere }, 963e569f6adSEtienne Carriere { 964e569f6adSEtienne Carriere .compatible = "st,stm32mp157-pinctrl", 965*b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 966*b4893304SGatien Chevallier .secure_control = false, 967*b4893304SGatien Chevallier }, 968e569f6adSEtienne Carriere }, 969e569f6adSEtienne Carriere { 970e569f6adSEtienne Carriere .compatible = "st,stm32mp157-z-pinctrl", 971*b4893304SGatien Chevallier .compat_data = &(struct bank_compat){ 972*b4893304SGatien Chevallier .gpioz = true, 973*b4893304SGatien Chevallier .secure_control = true, 974*b4893304SGatien Chevallier }, 975e569f6adSEtienne Carriere }, 9760e0435e2SEtienne Carriere { } 9770e0435e2SEtienne Carriere }; 9780e0435e2SEtienne Carriere 9790e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 9800e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 9810e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 9820e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 9830e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 9840e0435e2SEtienne Carriere }; 985