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> 154b5e93edSEtienne Carriere #include <io.h> 164b5e93edSEtienne Carriere #include <kernel/dt.h> 1765401337SJens Wiklander #include <kernel/boot.h> 184b5e93edSEtienne Carriere #include <kernel/panic.h> 194b5e93edSEtienne Carriere #include <kernel/spinlock.h> 20a2fc83d1SJerome Forissier #include <libfdt.h> 214b5e93edSEtienne Carriere #include <mm/core_memprot.h> 224b5e93edSEtienne Carriere #include <stdbool.h> 2369715ce9SEtienne Carriere #include <stdint.h> 244b5e93edSEtienne Carriere #include <stm32_util.h> 259818a481SEtienne Carriere #include <sys/queue.h> 264b5e93edSEtienne Carriere #include <trace.h> 274b5e93edSEtienne Carriere #include <util.h> 284b5e93edSEtienne Carriere 291001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 301001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 311001585eSEtienne Carriere #endif 321001585eSEtienne Carriere 334b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 344b5e93edSEtienne Carriere 354b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET 0x00 364b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET 0x04 374b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET 0x08 384b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET 0x0c 394b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET 0x10 404b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET 0x14 414b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET 0x18 424b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET 0x20 434b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET 0x24 444b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET 0x30 454b5e93edSEtienne Carriere 464b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT 0x8 474b5e93edSEtienne Carriere 484b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 494b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 504b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 51729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 524b5e93edSEtienne Carriere 534b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT 12 544b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 554b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT 8 564b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 574b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 584b5e93edSEtienne Carriere 599818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 609818a481SEtienne Carriere 6169715ce9SEtienne Carriere #define GPIO_MODE_INPUT U(0x0) 6269715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT U(0x1) 6369715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE U(0x2) 6469715ce9SEtienne Carriere #define GPIO_MODE_ANALOG U(0x3) 6569715ce9SEtienne Carriere 6669715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL U(0x0) 6769715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN U(0x1) 6869715ce9SEtienne Carriere 6969715ce9SEtienne Carriere #define GPIO_OSPEED_LOW U(0x0) 7069715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM U(0x1) 7169715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH U(0x2) 7269715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH U(0x3) 7369715ce9SEtienne Carriere 7469715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL U(0x0) 7569715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP U(0x1) 7669715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN U(0x2) 7769715ce9SEtienne Carriere 7869715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW U(0x0) 7969715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH U(0x1) 8069715ce9SEtienne Carriere 8169715ce9SEtienne Carriere /* 8269715ce9SEtienne Carriere * GPIO configuration description structured as single 16bit word 8369715ce9SEtienne Carriere * for efficient save/restore when GPIO pin suspends or resumes. 8469715ce9SEtienne Carriere * 8569715ce9SEtienne Carriere * @mode: One of GPIO_MODE_* 8669715ce9SEtienne Carriere * @otype: One of GPIO_OTYPE_* 8769715ce9SEtienne Carriere * @ospeed: One of GPIO_OSPEED_* 8869715ce9SEtienne Carriere * @pupd: One of GPIO_PUPD_* 8969715ce9SEtienne Carriere * @od: One of GPIO_OD_* 9069715ce9SEtienne Carriere * @af: Alternate function numerical ID between 0 and 15 9169715ce9SEtienne Carriere */ 9269715ce9SEtienne Carriere struct gpio_cfg { 9369715ce9SEtienne Carriere uint16_t mode: 2; 9469715ce9SEtienne Carriere uint16_t otype: 1; 9569715ce9SEtienne Carriere uint16_t ospeed: 2; 9669715ce9SEtienne Carriere uint16_t pupd: 2; 9769715ce9SEtienne Carriere uint16_t od: 1; 9869715ce9SEtienne Carriere uint16_t af: 4; 9969715ce9SEtienne Carriere }; 10069715ce9SEtienne Carriere 10169715ce9SEtienne Carriere /* 10269715ce9SEtienne Carriere * Description of a pin and its muxing 10369715ce9SEtienne Carriere * 10469715ce9SEtienne Carriere * @bank: GPIO bank identifier as assigned by the platform 10569715ce9SEtienne Carriere * @pin: Pin number in the GPIO bank 10669715ce9SEtienne Carriere * @cfg: Pin configuration 10769715ce9SEtienne Carriere */ 10869715ce9SEtienne Carriere struct stm32_pinctrl { 10969715ce9SEtienne Carriere uint8_t bank; 11069715ce9SEtienne Carriere uint8_t pin; 11169715ce9SEtienne Carriere struct gpio_cfg cfg; 11269715ce9SEtienne Carriere }; 11369715ce9SEtienne Carriere 114b38386fbSEtienne Carriere /* 115b38386fbSEtienne Carriere * struct stm32_pinctrl_array - Array of pins in a pin control state 116b38386fbSEtienne Carriere * @count: Number of cells in @pinctrl 117b38386fbSEtienne Carriere * @pinctrl: Pin control configuration 118b38386fbSEtienne Carriere */ 119b38386fbSEtienne Carriere struct stm32_pinctrl_array { 120b38386fbSEtienne Carriere size_t count; 121b38386fbSEtienne Carriere struct stm32_pinctrl pinctrl[]; 122b38386fbSEtienne Carriere }; 123b38386fbSEtienne Carriere 1249818a481SEtienne Carriere /** 1259818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 1269818a481SEtienne Carriere * 1279818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 1289818a481SEtienne Carriere * @clock: clock identifier. 129420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 1309818a481SEtienne Carriere * @ngpios: number of GPIOs. 1319818a481SEtienne Carriere * @bank_id: Id of the bank. 1329818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 1339818a481SEtienne Carriere * @sec_support: True if bank supports pin security protection, otherwise false 1349818a481SEtienne Carriere * @seccfgr: Secure configuration register value. 1359818a481SEtienne Carriere * @link: Link in bank list 1369818a481SEtienne Carriere */ 1379818a481SEtienne Carriere struct stm32_gpio_bank { 1389818a481SEtienne Carriere vaddr_t base; 1399818a481SEtienne Carriere struct clk *clock; 140420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 1419818a481SEtienne Carriere unsigned int ngpios; 1429818a481SEtienne Carriere unsigned int bank_id; 1439818a481SEtienne Carriere unsigned int lock; 1449818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 1459818a481SEtienne Carriere }; 1469818a481SEtienne Carriere 147e569f6adSEtienne Carriere /* 148e569f6adSEtienne Carriere * Compatibility information of supported banks 149e569f6adSEtienne Carriere * @gpioz True if bank is a GPIOZ bank 150e569f6adSEtienne Carriere */ 151e569f6adSEtienne Carriere struct bank_compat { 152e569f6adSEtienne Carriere bool gpioz; 153e569f6adSEtienne Carriere }; 154e569f6adSEtienne Carriere 1554b5e93edSEtienne Carriere static unsigned int gpio_lock; 1564b5e93edSEtienne Carriere 1579818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 1589818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 1599818a481SEtienne Carriere 160420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 161420a32c5SEtienne Carriere 162420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 163420a32c5SEtienne Carriere { 164420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 165420a32c5SEtienne Carriere } 166420a32c5SEtienne Carriere 167420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 168420a32c5SEtienne Carriere unsigned int gpio_pin) 169420a32c5SEtienne Carriere { 170420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 171420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 172420a32c5SEtienne Carriere unsigned int reg_offset = 0; 173420a32c5SEtienne Carriere unsigned int mode = 0; 174420a32c5SEtienne Carriere 175420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1762fd102ebSEtienne Carriere 1772fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1782fd102ebSEtienne Carriere panic(); 179420a32c5SEtienne Carriere 180420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 181420a32c5SEtienne Carriere GPIO_MODE_MASK; 182420a32c5SEtienne Carriere 183420a32c5SEtienne Carriere switch (mode) { 184420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 185420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 186420a32c5SEtienne Carriere break; 187420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 188420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 189420a32c5SEtienne Carriere break; 190420a32c5SEtienne Carriere default: 191420a32c5SEtienne Carriere panic(); 192420a32c5SEtienne Carriere } 193420a32c5SEtienne Carriere 194420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 195420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 196420a32c5SEtienne Carriere else 197420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 198420a32c5SEtienne Carriere 199420a32c5SEtienne Carriere clk_disable(bank->clock); 200420a32c5SEtienne Carriere 201420a32c5SEtienne Carriere return level; 202420a32c5SEtienne Carriere } 203420a32c5SEtienne Carriere 204420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 205420a32c5SEtienne Carriere enum gpio_level level) 206420a32c5SEtienne Carriere { 207420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 208420a32c5SEtienne Carriere 209420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2102fd102ebSEtienne Carriere 2112fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2122fd102ebSEtienne Carriere panic(); 213420a32c5SEtienne Carriere 214420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 215420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 216420a32c5SEtienne Carriere 217420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 218420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 219420a32c5SEtienne Carriere else 220420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 221420a32c5SEtienne Carriere 222420a32c5SEtienne Carriere clk_disable(bank->clock); 223420a32c5SEtienne Carriere } 224420a32c5SEtienne Carriere 225420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 226420a32c5SEtienne Carriere unsigned int gpio_pin) 227420a32c5SEtienne Carriere { 228420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 229420a32c5SEtienne Carriere uint32_t mode = 0; 230420a32c5SEtienne Carriere 231420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 2322fd102ebSEtienne Carriere 2332fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2342fd102ebSEtienne Carriere panic(); 235420a32c5SEtienne Carriere 236420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 237420a32c5SEtienne Carriere GPIO_MODE_MASK; 238420a32c5SEtienne Carriere 239420a32c5SEtienne Carriere clk_disable(bank->clock); 240420a32c5SEtienne Carriere 241420a32c5SEtienne Carriere switch (mode) { 242420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 243420a32c5SEtienne Carriere return GPIO_DIR_IN; 244420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 245420a32c5SEtienne Carriere return GPIO_DIR_OUT; 246420a32c5SEtienne Carriere default: 247420a32c5SEtienne Carriere panic(); 248420a32c5SEtienne Carriere } 249420a32c5SEtienne Carriere } 250420a32c5SEtienne Carriere 251420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 252420a32c5SEtienne Carriere unsigned int gpio_pin, 253420a32c5SEtienne Carriere enum gpio_dir direction) 254420a32c5SEtienne Carriere { 255420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 256420a32c5SEtienne Carriere uint32_t exceptions = 0; 257420a32c5SEtienne Carriere uint32_t mode = 0; 258420a32c5SEtienne Carriere 259420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 260420a32c5SEtienne Carriere 261420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 262420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 263420a32c5SEtienne Carriere else 264420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 265420a32c5SEtienne Carriere 2662fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2672fd102ebSEtienne Carriere panic(); 268420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 269420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 270420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 271420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 272420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 273420a32c5SEtienne Carriere clk_disable(bank->clock); 274420a32c5SEtienne Carriere } 275420a32c5SEtienne Carriere 276420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 277420a32c5SEtienne Carriere struct gpio *gpio) 278420a32c5SEtienne Carriere { 279420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 280420a32c5SEtienne Carriere free(gpio); 281420a32c5SEtienne Carriere } 282420a32c5SEtienne Carriere 283420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 284420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 285420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 286420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 287420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 288420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 289420a32c5SEtienne Carriere }; 290420a32c5SEtienne Carriere 291420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 292420a32c5SEtienne Carriere { 293420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 294420a32c5SEtienne Carriere } 295420a32c5SEtienne Carriere 296077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 2974b5e93edSEtienne Carriere { 298077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 2994b5e93edSEtienne Carriere 300077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 301077d486eSEtienne Carriere if (bank_id == bank->bank_id) 302077d486eSEtienne Carriere return bank; 303077d486eSEtienne Carriere 304077d486eSEtienne Carriere panic(); 305077d486eSEtienne Carriere } 306077d486eSEtienne Carriere 307077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 308b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin, 309b38386fbSEtienne Carriere struct gpio_cfg *cfg) 310077d486eSEtienne Carriere { 311077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 312077d486eSEtienne Carriere 313077d486eSEtienne Carriere if (clk_enable(bank->clock)) 314077d486eSEtienne Carriere panic(); 3154b5e93edSEtienne Carriere 3164b5e93edSEtienne Carriere /* 3174b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 3184b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 3194b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 3204b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 3214b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 3224b5e93edSEtienne Carriere */ 323077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 3244b5e93edSEtienne Carriere GPIO_MODE_MASK; 3254b5e93edSEtienne Carriere 326077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 3274b5e93edSEtienne Carriere 328077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 329077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 3304b5e93edSEtienne Carriere 331077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 3324b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 3334b5e93edSEtienne Carriere 334077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 3354b5e93edSEtienne Carriere 3364b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 337077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 338077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 3394b5e93edSEtienne Carriere else 340077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 3414b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 3424b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 3434b5e93edSEtienne Carriere 344077d486eSEtienne Carriere clk_disable(bank->clock); 3454b5e93edSEtienne Carriere } 3464b5e93edSEtienne Carriere 3474b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 348077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 3494b5e93edSEtienne Carriere { 350077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 35198dfcedaSEtienne Carriere uint32_t exceptions = 0; 3524b5e93edSEtienne Carriere 353077d486eSEtienne Carriere if (clk_enable(bank->clock)) 354077d486eSEtienne Carriere panic(); 35598dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 3564b5e93edSEtienne Carriere 3574b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 358077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 359bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 360bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 3614b5e93edSEtienne Carriere 3624b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 363077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 364bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 3654b5e93edSEtienne Carriere 3664b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 367077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 368bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 369bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 3704b5e93edSEtienne Carriere 3714b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 372077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 373bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 3744b5e93edSEtienne Carriere 3754b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 3764b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 377077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 378bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 379bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 3804b5e93edSEtienne Carriere } else { 3814b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 3824b5e93edSEtienne Carriere 383077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 384bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 385bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 3864b5e93edSEtienne Carriere } 3874b5e93edSEtienne Carriere 3884b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 389077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 3904b5e93edSEtienne Carriere 391c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 39298dfcedaSEtienne Carriere clk_disable(bank->clock); 3934b5e93edSEtienne Carriere } 3944b5e93edSEtienne Carriere 3954b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 396b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node, 3974b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 3984b5e93edSEtienne Carriere { 399b38386fbSEtienne Carriere const fdt32_t *cuint = NULL; 400b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL; 40110bcbd6cSEtienne Carriere int len = 0; 40210bcbd6cSEtienne Carriere uint32_t i = 0; 4034b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 4044b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 4054b5e93edSEtienne Carriere size_t found = 0; 4064b5e93edSEtienne Carriere 4074b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 4084b5e93edSEtienne Carriere if (!cuint) 4094b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 4104b5e93edSEtienne Carriere 4114b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 4124b5e93edSEtienne Carriere if (slewrate) 4134b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 4144b5e93edSEtienne Carriere 4154b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 4164b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 4174b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 4184b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 4194b5e93edSEtienne Carriere 4204b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 42110bcbd6cSEtienne Carriere uint32_t pincfg = 0; 42210bcbd6cSEtienne Carriere uint32_t bank = 0; 42310bcbd6cSEtienne Carriere uint32_t pin = 0; 42410bcbd6cSEtienne Carriere uint32_t mode = 0; 4254b5e93edSEtienne Carriere uint32_t alternate = 0; 426322cf9e3SEtienne Carriere uint32_t odata = 0; 4274b5e93edSEtienne Carriere bool opendrain = false; 4284b5e93edSEtienne Carriere 4294b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 4304b5e93edSEtienne Carriere cuint++; 4314b5e93edSEtienne Carriere 4324b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 4334b5e93edSEtienne Carriere 4344b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 4354b5e93edSEtienne Carriere 4364b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 4374b5e93edSEtienne Carriere 4384b5e93edSEtienne Carriere switch (mode) { 4394b5e93edSEtienne Carriere case 0: 4404b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 4414b5e93edSEtienne Carriere break; 4424b5e93edSEtienne Carriere case 1: 4434b5e93edSEtienne Carriere case 2: 4444b5e93edSEtienne Carriere case 3: 4454b5e93edSEtienne Carriere case 4: 4464b5e93edSEtienne Carriere case 5: 4474b5e93edSEtienne Carriere case 6: 4484b5e93edSEtienne Carriere case 7: 4494b5e93edSEtienne Carriere case 8: 4504b5e93edSEtienne Carriere case 9: 4514b5e93edSEtienne Carriere case 10: 4524b5e93edSEtienne Carriere case 11: 4534b5e93edSEtienne Carriere case 12: 4544b5e93edSEtienne Carriere case 13: 4554b5e93edSEtienne Carriere case 14: 4564b5e93edSEtienne Carriere case 15: 4574b5e93edSEtienne Carriere case 16: 4584b5e93edSEtienne Carriere alternate = mode - 1U; 4594b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 4604b5e93edSEtienne Carriere break; 4614b5e93edSEtienne Carriere case 17: 4624b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 4634b5e93edSEtienne Carriere break; 4644b5e93edSEtienne Carriere default: 4654b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 4664b5e93edSEtienne Carriere break; 4674b5e93edSEtienne Carriere } 4684b5e93edSEtienne Carriere 4694b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 4704b5e93edSEtienne Carriere opendrain = true; 4714b5e93edSEtienne Carriere 472322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 473322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 474322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 475322cf9e3SEtienne Carriere odata = 1; 476322cf9e3SEtienne Carriere } 477322cf9e3SEtienne Carriere 478322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 479322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 480322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 481322cf9e3SEtienne Carriere odata = 0; 482322cf9e3SEtienne Carriere } 483322cf9e3SEtienne Carriere 4844b5e93edSEtienne Carriere if (found < count) { 4854b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 4864b5e93edSEtienne Carriere 4874b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 4884b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 489b38386fbSEtienne Carriere ref->cfg.mode = mode; 490b38386fbSEtienne Carriere if (opendrain) 491b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN; 492b38386fbSEtienne Carriere else 493b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL; 494b38386fbSEtienne Carriere ref->cfg.ospeed = speed; 495b38386fbSEtienne Carriere ref->cfg.pupd = pull; 496b38386fbSEtienne Carriere ref->cfg.od = odata; 497b38386fbSEtienne Carriere ref->cfg.af = alternate; 4984b5e93edSEtienne Carriere } 4994b5e93edSEtienne Carriere 5004b5e93edSEtienne Carriere found++; 5014b5e93edSEtienne Carriere } 5024b5e93edSEtienne Carriere 5034b5e93edSEtienne Carriere return (int)found; 5044b5e93edSEtienne Carriere } 5054b5e93edSEtienne Carriere 506b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data, 507b357d34fSEtienne Carriere struct gpio **out_gpio) 508420a32c5SEtienne Carriere { 509b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 510420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 511420a32c5SEtienne Carriere struct gpio *gpio = NULL; 512420a32c5SEtienne Carriere unsigned int shift_1b = 0; 513420a32c5SEtienne Carriere unsigned int shift_2b = 0; 514420a32c5SEtienne Carriere uint32_t exceptions = 0; 515420a32c5SEtienne Carriere uint32_t otype = 0; 516420a32c5SEtienne Carriere uint32_t pupd = 0; 517420a32c5SEtienne Carriere uint32_t mode = 0; 518420a32c5SEtienne Carriere 519b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio); 520b357d34fSEtienne Carriere if (res) 521b357d34fSEtienne Carriere return res; 522420a32c5SEtienne Carriere 523420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 524420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 525420a32c5SEtienne Carriere free(gpio); 526b357d34fSEtienne Carriere return TEE_ERROR_GENERIC; 527420a32c5SEtienne Carriere } 528420a32c5SEtienne Carriere 529420a32c5SEtienne Carriere shift_1b = gpio->pin; 530420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 531420a32c5SEtienne Carriere 532420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 533420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 534420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 535420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 536420a32c5SEtienne Carriere else 537420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 538420a32c5SEtienne Carriere 539420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 540420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 541420a32c5SEtienne Carriere else 542420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 543420a32c5SEtienne Carriere 544420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 545420a32c5SEtienne Carriere panic(); 546420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 547420a32c5SEtienne Carriere 548420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 549420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 550420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 551420a32c5SEtienne Carriere 552420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 553420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 554420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 555420a32c5SEtienne Carriere 556420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 557420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 558420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 559420a32c5SEtienne Carriere 560420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 561420a32c5SEtienne Carriere clk_disable(bank->clock); 562420a32c5SEtienne Carriere 563420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 564420a32c5SEtienne Carriere 565b357d34fSEtienne Carriere *out_gpio = gpio; 566420a32c5SEtienne Carriere 567b357d34fSEtienne Carriere return TEE_SUCCESS; 568420a32c5SEtienne Carriere } 569420a32c5SEtienne Carriere 5709818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 5719818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 5729818a481SEtienne Carriere { 5739818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 5749818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5759818a481SEtienne Carriere int len = 0; 5769818a481SEtienne Carriere 5779818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 5789818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 5799818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 5809818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 5819818a481SEtienne Carriere 5829818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 5839818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 5849818a481SEtienne Carriere panic("Wrong st,bank-name property"); 5859818a481SEtienne Carriere 5869818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 5879818a481SEtienne Carriere } 5889818a481SEtienne Carriere 5899818a481SEtienne Carriere /* 5909818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 5919818a481SEtienne Carriere * registered in the GPIO bank link. 5929818a481SEtienne Carriere */ 5939818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 5949818a481SEtienne Carriere { 5959818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 5969818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5979818a481SEtienne Carriere 5989818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 5999818a481SEtienne Carriere if (bank->bank_id == bank_id) 6009818a481SEtienne Carriere return true; 6019818a481SEtienne Carriere 6029818a481SEtienne Carriere return false; 6039818a481SEtienne Carriere } 6049818a481SEtienne Carriere 6059818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 6069818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 607e569f6adSEtienne Carriere const void *compat_data, 6089818a481SEtienne Carriere int range_offset, 6099818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 6109818a481SEtienne Carriere { 611e569f6adSEtienne Carriere const struct bank_compat *compat = compat_data; 6129818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 6139818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6149818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6159818a481SEtienne Carriere struct io_pa_va pa_va = { }; 6169818a481SEtienne Carriere struct clk *clk = NULL; 6179818a481SEtienne Carriere size_t blen = 0; 6189818a481SEtienne Carriere paddr_t pa = 0; 6199818a481SEtienne Carriere int len = 0; 6209818a481SEtienne Carriere int i = 0; 6219818a481SEtienne Carriere 6229818a481SEtienne Carriere assert(out_bank); 6239818a481SEtienne Carriere 6249818a481SEtienne Carriere /* Probe deferrable devices first */ 6259818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 6269818a481SEtienne Carriere if (res) 6279818a481SEtienne Carriere return res; 6289818a481SEtienne Carriere 6299818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 6309818a481SEtienne Carriere if (!bank) 6319818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 6329818a481SEtienne Carriere 6339818a481SEtienne Carriere /* 6349818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 6359818a481SEtienne Carriere * but consider also the "ranges" translation property 6369818a481SEtienne Carriere */ 6379818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 6389818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 6399818a481SEtienne Carriere panic("missing reg property"); 6409818a481SEtienne Carriere 6419818a481SEtienne Carriere pa_va.pa = pa + range_offset; 6429818a481SEtienne Carriere 6439818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 6449818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 6459818a481SEtienne Carriere panic("missing reg size property"); 6469818a481SEtienne Carriere 6479818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 6489818a481SEtienne Carriere bank->base = io_pa_or_va_secure(&pa_va, blen); 6499818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 6509818a481SEtienne Carriere bank->clock = clk; 651420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 6529818a481SEtienne Carriere 6539818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 6549818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 6559818a481SEtienne Carriere len /= sizeof(*cuint); 6569818a481SEtienne Carriere if (len % 4) 6579818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 6589818a481SEtienne Carriere 6599818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 6609818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 6619818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 6629818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 6639818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 6649818a481SEtienne Carriere cuint += 4; 6659818a481SEtienne Carriere } 6669818a481SEtienne Carriere 667e569f6adSEtienne Carriere if (compat->gpioz) 668e569f6adSEtienne Carriere stm32mp_register_gpioz_pin_count(bank->ngpios); 669e569f6adSEtienne Carriere 6709818a481SEtienne Carriere *out_bank = bank; 6719818a481SEtienne Carriere return TEE_SUCCESS; 6729818a481SEtienne Carriere } 6739818a481SEtienne Carriere 674be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank) 675be53ee7bSEtienne Carriere { 676be53ee7bSEtienne Carriere unsigned int pin = 0; 677be53ee7bSEtienne Carriere 678*580e08cfSGatien Chevallier for (pin = 0; pin < bank->ngpios; pin++) 679be53ee7bSEtienne Carriere stm32_gpio_set_secure_cfg(bank->bank_id, pin, false); 680be53ee7bSEtienne Carriere } 681be53ee7bSEtienne Carriere 6829818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */ 6830e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 6849818a481SEtienne Carriere const void *compat_data) 6859818a481SEtienne Carriere { 6869818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 6879818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6889818a481SEtienne Carriere int range_offs = 0; 6899818a481SEtienne Carriere int b_node = 0; 6909818a481SEtienne Carriere int len = 0; 6919818a481SEtienne Carriere 6929818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 6939818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 6949818a481SEtienne Carriere if (!cuint) 6959818a481SEtienne Carriere panic("missing ranges property"); 6969818a481SEtienne Carriere 6979818a481SEtienne Carriere len /= sizeof(*cuint); 6989818a481SEtienne Carriere if (len == 3) 6999818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 7009818a481SEtienne Carriere 7019818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 7029818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 7039818a481SEtienne Carriere if (cuint) { 7049818a481SEtienne Carriere /* 7059818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 7069818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 7079818a481SEtienne Carriere * bank list. 7089818a481SEtienne Carriere */ 7099818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 7109818a481SEtienne Carriere 7119818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 7129818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 7139818a481SEtienne Carriere continue; 7149818a481SEtienne Carriere 7159818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 7169818a481SEtienne Carriere range_offs, &bank); 7179818a481SEtienne Carriere if (res) 7189818a481SEtienne Carriere return res; 7199818a481SEtienne Carriere 720420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 721420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 722420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 723420a32c5SEtienne Carriere if (res) 724420a32c5SEtienne Carriere panic(); 725420a32c5SEtienne Carriere 7269818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 727be53ee7bSEtienne Carriere 728be53ee7bSEtienne Carriere if (IS_ENABLED(CFG_STM32MP13)) 729be53ee7bSEtienne Carriere set_bank_gpio_non_secure(bank); 7309818a481SEtienne Carriere } else { 7319818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 7329818a481SEtienne Carriere panic(); 7339818a481SEtienne Carriere } 7349818a481SEtienne Carriere } 7359818a481SEtienne Carriere 7369818a481SEtienne Carriere return TEE_SUCCESS; 7379818a481SEtienne Carriere } 7389818a481SEtienne Carriere 739077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 740077d486eSEtienne Carriere bool secure) 7414b5e93edSEtienne Carriere { 742077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 74398dfcedaSEtienne Carriere uint32_t exceptions = 0; 7444b5e93edSEtienne Carriere 745077d486eSEtienne Carriere if (clk_enable(bank->clock)) 746077d486eSEtienne Carriere panic(); 74798dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 7484b5e93edSEtienne Carriere 7494b5e93edSEtienne Carriere if (secure) 750077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7514b5e93edSEtienne Carriere else 752077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 7534b5e93edSEtienne Carriere 754c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 75598dfcedaSEtienne Carriere clk_disable(bank->clock); 7564b5e93edSEtienne Carriere } 7570e0435e2SEtienne Carriere 758b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 759b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf) 760b38386fbSEtienne Carriere { 761b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv; 762b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl; 763b38386fbSEtienne Carriere size_t pin_count = ref->count; 764b38386fbSEtienne Carriere size_t n = 0; 765b38386fbSEtienne Carriere 766b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++) 767b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg); 768b38386fbSEtienne Carriere 769b38386fbSEtienne Carriere return TEE_SUCCESS; 770b38386fbSEtienne Carriere } 771b38386fbSEtienne Carriere 772b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf) 773b38386fbSEtienne Carriere { 774b38386fbSEtienne Carriere free(conf); 775b38386fbSEtienne Carriere } 776b38386fbSEtienne Carriere 777b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = { 778b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply, 779b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free, 780b38386fbSEtienne Carriere }; 781b38386fbSEtienne Carriere 782b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops); 783b38386fbSEtienne Carriere 78470ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl, 78570ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin, 78670ac0db5SEtienne Carriere unsigned int *count) 78770ac0db5SEtienne Carriere { 78870ac0db5SEtienne Carriere size_t conf_index = 0; 78970ac0db5SEtienne Carriere size_t pin_count = 0; 79070ac0db5SEtienne Carriere size_t n = 0; 79170ac0db5SEtienne Carriere 79270ac0db5SEtienne Carriere assert(count); 79370ac0db5SEtienne Carriere if (!pinctrl) 79470ac0db5SEtienne Carriere goto out; 79570ac0db5SEtienne Carriere 79670ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 79770ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 79870ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 79970ac0db5SEtienne Carriere 80070ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */ 80170ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 80270ac0db5SEtienne Carriere continue; 80370ac0db5SEtienne Carriere 80470ac0db5SEtienne Carriere if (bank || pin) { 80570ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) { 80670ac0db5SEtienne Carriere if (bank && pin_count < *count) 80770ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank; 80870ac0db5SEtienne Carriere if (pin && pin_count < *count) 80970ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin; 81070ac0db5SEtienne Carriere pin_count++; 81170ac0db5SEtienne Carriere } 81270ac0db5SEtienne Carriere } else { 81370ac0db5SEtienne Carriere pin_count += ref->count; 81470ac0db5SEtienne Carriere } 81570ac0db5SEtienne Carriere } 81670ac0db5SEtienne Carriere 81770ac0db5SEtienne Carriere out: 81870ac0db5SEtienne Carriere *count = pin_count; 81970ac0db5SEtienne Carriere } 82070ac0db5SEtienne Carriere 8217f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure) 8227f823a77SEtienne Carriere { 8237f823a77SEtienne Carriere size_t conf_index = 0; 8247f823a77SEtienne Carriere 8257f823a77SEtienne Carriere if (!pinctrl) 8267f823a77SEtienne Carriere return; 8277f823a77SEtienne Carriere 8287f823a77SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 8297f823a77SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 8307f823a77SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 8317f823a77SEtienne Carriere struct stm32_pinctrl *pc = NULL; 8327f823a77SEtienne Carriere size_t n = 0; 8337f823a77SEtienne Carriere 8347f823a77SEtienne Carriere for (n = 0; n < ref->count; n++) { 8357f823a77SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 8367f823a77SEtienne Carriere continue; 8377f823a77SEtienne Carriere 8387f823a77SEtienne Carriere pc = ref->pinctrl + n; 8397f823a77SEtienne Carriere stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure); 8407f823a77SEtienne Carriere } 8417f823a77SEtienne Carriere } 8427f823a77SEtienne Carriere } 8437f823a77SEtienne Carriere 844b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */ 845b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs, 846b38386fbSEtienne Carriere void *data __unused, 847b38386fbSEtienne Carriere struct pinconf **out_pinconf) 848b38386fbSEtienne Carriere { 849b38386fbSEtienne Carriere struct conf { 850b38386fbSEtienne Carriere struct pinconf pinconf; 851b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref; 852b38386fbSEtienne Carriere } *loc_conf = NULL; 853b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL; 854b38386fbSEtienne Carriere struct pinconf *pinconf = NULL; 855b38386fbSEtienne Carriere const void *fdt = NULL; 856b38386fbSEtienne Carriere size_t pin_count = 0; 857b38386fbSEtienne Carriere int pinctrl_node = 0; 858b38386fbSEtienne Carriere int pinmux_node = 0; 859b38386fbSEtienne Carriere int count = 0; 860b38386fbSEtienne Carriere 861b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node; 862b38386fbSEtienne Carriere fdt = pargs->fdt; 863b38386fbSEtienne Carriere assert(fdt && pinctrl_node); 864b38386fbSEtienne Carriere 865b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 866b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count)) 867b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t); 868b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND) 869b38386fbSEtienne Carriere panic(); 870b38386fbSEtienne Carriere } 871b38386fbSEtienne Carriere 872b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count); 873b38386fbSEtienne Carriere if (!loc_conf) 874b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 875b38386fbSEtienne Carriere 876b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf; 877b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops; 878b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref; 879b38386fbSEtienne Carriere 880b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count; 881b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl; 882b38386fbSEtienne Carriere 883b38386fbSEtienne Carriere count = 0; 884b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 885b38386fbSEtienne Carriere int found = 0; 886b38386fbSEtienne Carriere 887b38386fbSEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count, 888b38386fbSEtienne Carriere pin_count - count); 889b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) { 890b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */ 891b38386fbSEtienne Carriere panic(); 892b38386fbSEtienne Carriere } 893b38386fbSEtienne Carriere 894b38386fbSEtienne Carriere count += found; 895b38386fbSEtienne Carriere } 896b38386fbSEtienne Carriere 897b38386fbSEtienne Carriere *out_pinconf = pinconf; 898b38386fbSEtienne Carriere 899b38386fbSEtienne Carriere return TEE_SUCCESS; 900b38386fbSEtienne Carriere } 901b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 902b38386fbSEtienne Carriere 9030e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 9040e0435e2SEtienne Carriere const void *compat_data) 9050e0435e2SEtienne Carriere { 906b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 907b38386fbSEtienne Carriere 9080e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 909b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data); 910b38386fbSEtienne Carriere if (res) 911b38386fbSEtienne Carriere return res; 912b38386fbSEtienne Carriere 913b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 914b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get, 915b38386fbSEtienne Carriere (void *)compat_data); 916b38386fbSEtienne Carriere if (res) 917b38386fbSEtienne Carriere return res; 918b38386fbSEtienne Carriere #endif 919b38386fbSEtienne Carriere 920b38386fbSEtienne Carriere return TEE_SUCCESS; 9210e0435e2SEtienne Carriere } 9220e0435e2SEtienne Carriere 9230e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 924e569f6adSEtienne Carriere { 925e569f6adSEtienne Carriere .compatible = "st,stm32mp135-pinctrl", 926e569f6adSEtienne Carriere .compat_data = &(struct bank_compat){ }, 927e569f6adSEtienne Carriere 928e569f6adSEtienne Carriere }, 929e569f6adSEtienne Carriere { 930e569f6adSEtienne Carriere .compatible = "st,stm32mp157-pinctrl", 931e569f6adSEtienne Carriere .compat_data = &(struct bank_compat){ }, 932e569f6adSEtienne Carriere }, 933e569f6adSEtienne Carriere { 934e569f6adSEtienne Carriere .compatible = "st,stm32mp157-z-pinctrl", 935e569f6adSEtienne Carriere .compat_data = &(struct bank_compat){ .gpioz = true, }, 936e569f6adSEtienne Carriere }, 9370e0435e2SEtienne Carriere { } 9380e0435e2SEtienne Carriere }; 9390e0435e2SEtienne Carriere 9400e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 9410e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 9420e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 9430e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 9440e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 9450e0435e2SEtienne Carriere }; 946