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> 997391ffbSEtienne Carriere #include <drivers/clk.h> 1097391ffbSEtienne Carriere #include <drivers/clk_dt.h> 11420a32c5SEtienne Carriere #include <drivers/gpio.h> 12b38386fbSEtienne Carriere #include <drivers/pinctrl.h> 134b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h> 144b5e93edSEtienne Carriere #include <io.h> 154b5e93edSEtienne Carriere #include <kernel/dt.h> 1665401337SJens Wiklander #include <kernel/boot.h> 174b5e93edSEtienne Carriere #include <kernel/panic.h> 184b5e93edSEtienne Carriere #include <kernel/spinlock.h> 19a2fc83d1SJerome Forissier #include <libfdt.h> 204b5e93edSEtienne Carriere #include <mm/core_memprot.h> 214b5e93edSEtienne Carriere #include <stdbool.h> 224b5e93edSEtienne Carriere #include <stm32_util.h> 239818a481SEtienne Carriere #include <sys/queue.h> 244b5e93edSEtienne Carriere #include <trace.h> 254b5e93edSEtienne Carriere #include <util.h> 264b5e93edSEtienne Carriere 271001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO 281001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO 291001585eSEtienne Carriere #endif 301001585eSEtienne Carriere 314b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 324b5e93edSEtienne Carriere 334b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET 0x00 344b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET 0x04 354b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET 0x08 364b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET 0x0c 374b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET 0x10 384b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET 0x14 394b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET 0x18 404b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET 0x20 414b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET 0x24 424b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET 0x30 434b5e93edSEtienne Carriere 444b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT 0x8 454b5e93edSEtienne Carriere 464b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 474b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 484b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 49729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 504b5e93edSEtienne Carriere 514b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT 12 524b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 534b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT 8 544b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 554b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 564b5e93edSEtienne Carriere 579818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 589818a481SEtienne Carriere 59b38386fbSEtienne Carriere /* 60b38386fbSEtienne Carriere * struct stm32_pinctrl_array - Array of pins in a pin control state 61b38386fbSEtienne Carriere * @count: Number of cells in @pinctrl 62b38386fbSEtienne Carriere * @pinctrl: Pin control configuration 63b38386fbSEtienne Carriere */ 64b38386fbSEtienne Carriere struct stm32_pinctrl_array { 65b38386fbSEtienne Carriere size_t count; 66b38386fbSEtienne Carriere struct stm32_pinctrl pinctrl[]; 67b38386fbSEtienne Carriere }; 68b38386fbSEtienne Carriere 699818a481SEtienne Carriere /** 709818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 719818a481SEtienne Carriere * 729818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 739818a481SEtienne Carriere * @clock: clock identifier. 74420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 759818a481SEtienne Carriere * @ngpios: number of GPIOs. 769818a481SEtienne Carriere * @bank_id: Id of the bank. 779818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 789818a481SEtienne Carriere * @sec_support: True if bank supports pin security protection, otherwise false 799818a481SEtienne Carriere * @seccfgr: Secure configuration register value. 809818a481SEtienne Carriere * @link: Link in bank list 819818a481SEtienne Carriere */ 829818a481SEtienne Carriere struct stm32_gpio_bank { 839818a481SEtienne Carriere vaddr_t base; 849818a481SEtienne Carriere struct clk *clock; 85420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 869818a481SEtienne Carriere unsigned int ngpios; 879818a481SEtienne Carriere unsigned int bank_id; 889818a481SEtienne Carriere unsigned int lock; 899818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 909818a481SEtienne Carriere }; 919818a481SEtienne Carriere 924b5e93edSEtienne Carriere static unsigned int gpio_lock; 934b5e93edSEtienne Carriere 949818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 959818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 969818a481SEtienne Carriere 97420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 98420a32c5SEtienne Carriere 99420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 100420a32c5SEtienne Carriere { 101420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 102420a32c5SEtienne Carriere } 103420a32c5SEtienne Carriere 104420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 105420a32c5SEtienne Carriere unsigned int gpio_pin) 106420a32c5SEtienne Carriere { 107420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 108420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 109420a32c5SEtienne Carriere unsigned int reg_offset = 0; 110420a32c5SEtienne Carriere unsigned int mode = 0; 111420a32c5SEtienne Carriere 112420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1132fd102ebSEtienne Carriere 1142fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1152fd102ebSEtienne Carriere panic(); 116420a32c5SEtienne Carriere 117420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 118420a32c5SEtienne Carriere GPIO_MODE_MASK; 119420a32c5SEtienne Carriere 120420a32c5SEtienne Carriere switch (mode) { 121420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 122420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 123420a32c5SEtienne Carriere break; 124420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 125420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 126420a32c5SEtienne Carriere break; 127420a32c5SEtienne Carriere default: 128420a32c5SEtienne Carriere panic(); 129420a32c5SEtienne Carriere } 130420a32c5SEtienne Carriere 131420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 132420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 133420a32c5SEtienne Carriere else 134420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 135420a32c5SEtienne Carriere 136420a32c5SEtienne Carriere clk_disable(bank->clock); 137420a32c5SEtienne Carriere 138420a32c5SEtienne Carriere return level; 139420a32c5SEtienne Carriere } 140420a32c5SEtienne Carriere 141420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 142420a32c5SEtienne Carriere enum gpio_level level) 143420a32c5SEtienne Carriere { 144420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 145420a32c5SEtienne Carriere 146420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1472fd102ebSEtienne Carriere 1482fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1492fd102ebSEtienne Carriere panic(); 150420a32c5SEtienne Carriere 151420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 152420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 153420a32c5SEtienne Carriere 154420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 155420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 156420a32c5SEtienne Carriere else 157420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 158420a32c5SEtienne Carriere 159420a32c5SEtienne Carriere clk_disable(bank->clock); 160420a32c5SEtienne Carriere } 161420a32c5SEtienne Carriere 162420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 163420a32c5SEtienne Carriere unsigned int gpio_pin) 164420a32c5SEtienne Carriere { 165420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 166420a32c5SEtienne Carriere uint32_t mode = 0; 167420a32c5SEtienne Carriere 168420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 1692fd102ebSEtienne Carriere 1702fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 1712fd102ebSEtienne Carriere panic(); 172420a32c5SEtienne Carriere 173420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 174420a32c5SEtienne Carriere GPIO_MODE_MASK; 175420a32c5SEtienne Carriere 176420a32c5SEtienne Carriere clk_disable(bank->clock); 177420a32c5SEtienne Carriere 178420a32c5SEtienne Carriere switch (mode) { 179420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 180420a32c5SEtienne Carriere return GPIO_DIR_IN; 181420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 182420a32c5SEtienne Carriere return GPIO_DIR_OUT; 183420a32c5SEtienne Carriere default: 184420a32c5SEtienne Carriere panic(); 185420a32c5SEtienne Carriere } 186420a32c5SEtienne Carriere } 187420a32c5SEtienne Carriere 188420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 189420a32c5SEtienne Carriere unsigned int gpio_pin, 190420a32c5SEtienne Carriere enum gpio_dir direction) 191420a32c5SEtienne Carriere { 192420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 193420a32c5SEtienne Carriere uint32_t exceptions = 0; 194420a32c5SEtienne Carriere uint32_t mode = 0; 195420a32c5SEtienne Carriere 196420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 197420a32c5SEtienne Carriere 198420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 199420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 200420a32c5SEtienne Carriere else 201420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 202420a32c5SEtienne Carriere 2032fd102ebSEtienne Carriere if (clk_enable(bank->clock)) 2042fd102ebSEtienne Carriere panic(); 205420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 206420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 207420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 208420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 209420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 210420a32c5SEtienne Carriere clk_disable(bank->clock); 211420a32c5SEtienne Carriere } 212420a32c5SEtienne Carriere 213420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 214420a32c5SEtienne Carriere struct gpio *gpio) 215420a32c5SEtienne Carriere { 216420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 217420a32c5SEtienne Carriere free(gpio); 218420a32c5SEtienne Carriere } 219420a32c5SEtienne Carriere 220420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 221420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 222420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 223420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 224420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 225420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 226420a32c5SEtienne Carriere }; 227420a32c5SEtienne Carriere 228420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 229420a32c5SEtienne Carriere { 230420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 231420a32c5SEtienne Carriere } 232420a32c5SEtienne Carriere 233077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 2344b5e93edSEtienne Carriere { 235077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 2364b5e93edSEtienne Carriere 237077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 238077d486eSEtienne Carriere if (bank_id == bank->bank_id) 239077d486eSEtienne Carriere return bank; 240077d486eSEtienne Carriere 241077d486eSEtienne Carriere panic(); 242077d486eSEtienne Carriere } 243077d486eSEtienne Carriere 244077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 245b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin, 246b38386fbSEtienne Carriere struct gpio_cfg *cfg) 247077d486eSEtienne Carriere { 248077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 249077d486eSEtienne Carriere 250077d486eSEtienne Carriere if (clk_enable(bank->clock)) 251077d486eSEtienne Carriere panic(); 2524b5e93edSEtienne Carriere 2534b5e93edSEtienne Carriere /* 2544b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 2554b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 2564b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 2574b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 2584b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 2594b5e93edSEtienne Carriere */ 260077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 2614b5e93edSEtienne Carriere GPIO_MODE_MASK; 2624b5e93edSEtienne Carriere 263077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 2644b5e93edSEtienne Carriere 265077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 266077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 2674b5e93edSEtienne Carriere 268077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 2694b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 2704b5e93edSEtienne Carriere 271077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 2724b5e93edSEtienne Carriere 2734b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 274077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 275077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 2764b5e93edSEtienne Carriere else 277077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 2784b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 2794b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 2804b5e93edSEtienne Carriere 281077d486eSEtienne Carriere clk_disable(bank->clock); 2824b5e93edSEtienne Carriere } 2834b5e93edSEtienne Carriere 2844b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 285077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 2864b5e93edSEtienne Carriere { 287077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 28898dfcedaSEtienne Carriere uint32_t exceptions = 0; 2894b5e93edSEtienne Carriere 290077d486eSEtienne Carriere if (clk_enable(bank->clock)) 291077d486eSEtienne Carriere panic(); 29298dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 2934b5e93edSEtienne Carriere 2944b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 295077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 296bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 297bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 2984b5e93edSEtienne Carriere 2994b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 300077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 301bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 3024b5e93edSEtienne Carriere 3034b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 304077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 305bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 306bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 3074b5e93edSEtienne Carriere 3084b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 309077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 310bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 3114b5e93edSEtienne Carriere 3124b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 3134b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 314077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 315bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 316bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 3174b5e93edSEtienne Carriere } else { 3184b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 3194b5e93edSEtienne Carriere 320077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 321bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 322bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 3234b5e93edSEtienne Carriere } 3244b5e93edSEtienne Carriere 3254b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 326077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 3274b5e93edSEtienne Carriere 328c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 32998dfcedaSEtienne Carriere clk_disable(bank->clock); 3304b5e93edSEtienne Carriere } 3314b5e93edSEtienne Carriere 332b38386fbSEtienne Carriere #if !defined(CFG_DRIVERS_PINCTRL) 3334b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3344b5e93edSEtienne Carriere { 33510bcbd6cSEtienne Carriere size_t n = 0; 3364b5e93edSEtienne Carriere 3374b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3384b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3394b5e93edSEtienne Carriere &pinctrl[n].active_cfg); 3404b5e93edSEtienne Carriere } 3414b5e93edSEtienne Carriere 3424b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3434b5e93edSEtienne Carriere { 34410bcbd6cSEtienne Carriere size_t n = 0; 3454b5e93edSEtienne Carriere 3464b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3474b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3484b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3494b5e93edSEtienne Carriere } 3504b5e93edSEtienne Carriere 3514b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3524b5e93edSEtienne Carriere { 35310bcbd6cSEtienne Carriere size_t n = 0; 3544b5e93edSEtienne Carriere 3554b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3564b5e93edSEtienne Carriere get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3574b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3584b5e93edSEtienne Carriere } 3594b5e93edSEtienne Carriere 36042f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */ 361b38386fbSEtienne Carriere static void ckeck_gpio_bank(const void *fdt, uint32_t bank, int pinctrl_node) 3624b5e93edSEtienne Carriere { 36310bcbd6cSEtienne Carriere int pinctrl_subnode = 0; 3644b5e93edSEtienne Carriere 3654b5e93edSEtienne Carriere fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { 36610bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 3674b5e93edSEtienne Carriere 3684b5e93edSEtienne Carriere if (fdt_getprop(fdt, pinctrl_subnode, 3694b5e93edSEtienne Carriere "gpio-controller", NULL) == NULL) 3704b5e93edSEtienne Carriere continue; 3714b5e93edSEtienne Carriere 3724b5e93edSEtienne Carriere /* Check bank register offset matches platform assumptions */ 3734b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); 3744b5e93edSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 375563f6249SEtienne Carriere continue; 3764b5e93edSEtienne Carriere 3774b5e93edSEtienne Carriere /* Check controller is enabled */ 378f354a5d8SGatien Chevallier if (fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED) 3794b5e93edSEtienne Carriere panic(); 3804b5e93edSEtienne Carriere 3814b5e93edSEtienne Carriere return; 3824b5e93edSEtienne Carriere } 3834b5e93edSEtienne Carriere 3844b5e93edSEtienne Carriere panic(); 3854b5e93edSEtienne Carriere } 386b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 3874b5e93edSEtienne Carriere 3884b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 389b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node, 3904b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 3914b5e93edSEtienne Carriere { 392b38386fbSEtienne Carriere const fdt32_t *cuint = NULL; 393b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL; 39410bcbd6cSEtienne Carriere int len = 0; 395b38386fbSEtienne Carriere int __maybe_unused pinctrl_node = 0; 39610bcbd6cSEtienne Carriere uint32_t i = 0; 3974b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 3984b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 3994b5e93edSEtienne Carriere size_t found = 0; 4004b5e93edSEtienne Carriere 4014b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 4024b5e93edSEtienne Carriere if (!cuint) 4034b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 4044b5e93edSEtienne Carriere 405b38386fbSEtienne Carriere #if !defined(CFG_DRIVERS_PINCTRL) 4064b5e93edSEtienne Carriere pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); 4074b5e93edSEtienne Carriere if (pinctrl_node < 0) 4084b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 409b38386fbSEtienne Carriere #endif 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 484b38386fbSEtienne Carriere #if !defined(CFG_DRIVERS_PINCTRL) 4854b5e93edSEtienne Carriere /* Check GPIO bank clock/base address against platform */ 4864b5e93edSEtienne Carriere ckeck_gpio_bank(fdt, bank, pinctrl_node); 487b38386fbSEtienne Carriere #endif 4884b5e93edSEtienne Carriere 4894b5e93edSEtienne Carriere if (found < count) { 4904b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 4914b5e93edSEtienne Carriere 4924b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 4934b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 494b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 495b38386fbSEtienne Carriere ref->cfg.mode = mode; 496b38386fbSEtienne Carriere if (opendrain) 497b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN; 498b38386fbSEtienne Carriere else 499b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL; 500b38386fbSEtienne Carriere ref->cfg.ospeed = speed; 501b38386fbSEtienne Carriere ref->cfg.pupd = pull; 502b38386fbSEtienne Carriere ref->cfg.od = odata; 503b38386fbSEtienne Carriere ref->cfg.af = alternate; 504b38386fbSEtienne Carriere #else 5054b5e93edSEtienne Carriere ref->active_cfg.mode = mode; 5064b5e93edSEtienne Carriere ref->active_cfg.otype = opendrain ? 1 : 0; 5074b5e93edSEtienne Carriere ref->active_cfg.ospeed = speed; 5084b5e93edSEtienne Carriere ref->active_cfg.pupd = pull; 509322cf9e3SEtienne Carriere ref->active_cfg.od = odata; 5104b5e93edSEtienne Carriere ref->active_cfg.af = alternate; 5114b5e93edSEtienne Carriere /* Default to analog mode for standby state */ 5124b5e93edSEtienne Carriere ref->standby_cfg.mode = GPIO_MODE_ANALOG; 5134b5e93edSEtienne Carriere ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL; 514b38386fbSEtienne Carriere #endif 5154b5e93edSEtienne Carriere } 5164b5e93edSEtienne Carriere 5174b5e93edSEtienne Carriere found++; 5184b5e93edSEtienne Carriere } 5194b5e93edSEtienne Carriere 5204b5e93edSEtienne Carriere return (int)found; 5214b5e93edSEtienne Carriere } 5224b5e93edSEtienne Carriere 523b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data, 524b357d34fSEtienne Carriere struct gpio **out_gpio) 525420a32c5SEtienne Carriere { 526b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 527420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 528420a32c5SEtienne Carriere struct gpio *gpio = NULL; 529420a32c5SEtienne Carriere unsigned int shift_1b = 0; 530420a32c5SEtienne Carriere unsigned int shift_2b = 0; 531420a32c5SEtienne Carriere uint32_t exceptions = 0; 532420a32c5SEtienne Carriere uint32_t otype = 0; 533420a32c5SEtienne Carriere uint32_t pupd = 0; 534420a32c5SEtienne Carriere uint32_t mode = 0; 535420a32c5SEtienne Carriere 536b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio); 537b357d34fSEtienne Carriere if (res) 538b357d34fSEtienne Carriere return res; 539420a32c5SEtienne Carriere 540420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 541420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 542420a32c5SEtienne Carriere free(gpio); 543b357d34fSEtienne Carriere return TEE_ERROR_GENERIC; 544420a32c5SEtienne Carriere } 545420a32c5SEtienne Carriere 546420a32c5SEtienne Carriere shift_1b = gpio->pin; 547420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 548420a32c5SEtienne Carriere 549420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 550420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 551420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 552420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 553420a32c5SEtienne Carriere else 554420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 555420a32c5SEtienne Carriere 556420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 557420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 558420a32c5SEtienne Carriere else 559420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 560420a32c5SEtienne Carriere 561420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 562420a32c5SEtienne Carriere panic(); 563420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 564420a32c5SEtienne Carriere 565420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 566420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 567420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 568420a32c5SEtienne Carriere 569420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 570420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 571420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 572420a32c5SEtienne Carriere 573420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 574420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 575420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 576420a32c5SEtienne Carriere 577420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 578420a32c5SEtienne Carriere clk_disable(bank->clock); 579420a32c5SEtienne Carriere 580420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 581420a32c5SEtienne Carriere 582b357d34fSEtienne Carriere *out_gpio = gpio; 583420a32c5SEtienne Carriere 584b357d34fSEtienne Carriere return TEE_SUCCESS; 585420a32c5SEtienne Carriere } 586420a32c5SEtienne Carriere 5879818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 5889818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 5899818a481SEtienne Carriere { 5909818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 5919818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5929818a481SEtienne Carriere int len = 0; 5939818a481SEtienne Carriere 5949818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 5959818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 5969818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 5979818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 5989818a481SEtienne Carriere 5999818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 6009818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 6019818a481SEtienne Carriere panic("Wrong st,bank-name property"); 6029818a481SEtienne Carriere 6039818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 6049818a481SEtienne Carriere } 6059818a481SEtienne Carriere 6069818a481SEtienne Carriere /* 6079818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 6089818a481SEtienne Carriere * registered in the GPIO bank link. 6099818a481SEtienne Carriere */ 6109818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 6119818a481SEtienne Carriere { 6129818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 6139818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6149818a481SEtienne Carriere 6159818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 6169818a481SEtienne Carriere if (bank->bank_id == bank_id) 6179818a481SEtienne Carriere return true; 6189818a481SEtienne Carriere 6199818a481SEtienne Carriere return false; 6209818a481SEtienne Carriere } 6219818a481SEtienne Carriere 6229818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 6239818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 6249818a481SEtienne Carriere const void *compat_data __unused, 6259818a481SEtienne Carriere int range_offset, 6269818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 6279818a481SEtienne Carriere { 6289818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 6299818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6309818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6319818a481SEtienne Carriere struct io_pa_va pa_va = { }; 6329818a481SEtienne Carriere struct clk *clk = NULL; 6339818a481SEtienne Carriere size_t blen = 0; 6349818a481SEtienne Carriere paddr_t pa = 0; 6359818a481SEtienne Carriere int len = 0; 6369818a481SEtienne Carriere int i = 0; 6379818a481SEtienne Carriere 6389818a481SEtienne Carriere assert(out_bank); 6399818a481SEtienne Carriere 6409818a481SEtienne Carriere /* Probe deferrable devices first */ 6419818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 6429818a481SEtienne Carriere if (res) 6439818a481SEtienne Carriere return res; 6449818a481SEtienne Carriere 6459818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 6469818a481SEtienne Carriere if (!bank) 6479818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 6489818a481SEtienne Carriere 6499818a481SEtienne Carriere /* 6509818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 6519818a481SEtienne Carriere * but consider also the "ranges" translation property 6529818a481SEtienne Carriere */ 6539818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 6549818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 6559818a481SEtienne Carriere panic("missing reg property"); 6569818a481SEtienne Carriere 6579818a481SEtienne Carriere pa_va.pa = pa + range_offset; 6589818a481SEtienne Carriere 6599818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 6609818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 6619818a481SEtienne Carriere panic("missing reg size property"); 6629818a481SEtienne Carriere 6639818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 6649818a481SEtienne Carriere bank->base = io_pa_or_va_secure(&pa_va, blen); 6659818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 6669818a481SEtienne Carriere bank->clock = clk; 667420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 6689818a481SEtienne Carriere 6699818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 6709818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 6719818a481SEtienne Carriere len /= sizeof(*cuint); 6729818a481SEtienne Carriere if (len % 4) 6739818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 6749818a481SEtienne Carriere 6759818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 6769818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 6779818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 6789818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 6799818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 6809818a481SEtienne Carriere cuint += 4; 6819818a481SEtienne Carriere } 6829818a481SEtienne Carriere 6839818a481SEtienne Carriere *out_bank = bank; 6849818a481SEtienne Carriere return TEE_SUCCESS; 6859818a481SEtienne Carriere } 6869818a481SEtienne Carriere 687be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank) 688be53ee7bSEtienne Carriere { 689be53ee7bSEtienne Carriere unsigned int pin = 0; 690be53ee7bSEtienne Carriere 691be53ee7bSEtienne Carriere for (pin = 0; pin <= bank->ngpios; pin++) 692be53ee7bSEtienne Carriere stm32_gpio_set_secure_cfg(bank->bank_id, pin, false); 693be53ee7bSEtienne Carriere } 694be53ee7bSEtienne Carriere 6959818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */ 6960e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 6979818a481SEtienne Carriere const void *compat_data) 6989818a481SEtienne Carriere { 6999818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 7009818a481SEtienne Carriere const fdt32_t *cuint = NULL; 7019818a481SEtienne Carriere int range_offs = 0; 7029818a481SEtienne Carriere int b_node = 0; 7039818a481SEtienne Carriere int len = 0; 7049818a481SEtienne Carriere 7059818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 7069818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 7079818a481SEtienne Carriere if (!cuint) 7089818a481SEtienne Carriere panic("missing ranges property"); 7099818a481SEtienne Carriere 7109818a481SEtienne Carriere len /= sizeof(*cuint); 7119818a481SEtienne Carriere if (len == 3) 7129818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 7139818a481SEtienne Carriere 7149818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 7159818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 7169818a481SEtienne Carriere if (cuint) { 7179818a481SEtienne Carriere /* 7189818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 7199818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 7209818a481SEtienne Carriere * bank list. 7219818a481SEtienne Carriere */ 7229818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 7239818a481SEtienne Carriere 7249818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 7259818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 7269818a481SEtienne Carriere continue; 7279818a481SEtienne Carriere 7289818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 7299818a481SEtienne Carriere range_offs, &bank); 7309818a481SEtienne Carriere if (res) 7319818a481SEtienne Carriere return res; 7329818a481SEtienne Carriere 733420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 734420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 735420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 736420a32c5SEtienne Carriere if (res) 737420a32c5SEtienne Carriere panic(); 738420a32c5SEtienne Carriere 7399818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 740be53ee7bSEtienne Carriere 741be53ee7bSEtienne Carriere if (IS_ENABLED(CFG_STM32MP13)) 742be53ee7bSEtienne Carriere set_bank_gpio_non_secure(bank); 7439818a481SEtienne Carriere } else { 7449818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 7459818a481SEtienne Carriere panic(); 7469818a481SEtienne Carriere } 7479818a481SEtienne Carriere } 7489818a481SEtienne Carriere 7499818a481SEtienne Carriere return TEE_SUCCESS; 7509818a481SEtienne Carriere } 7519818a481SEtienne Carriere 752b38386fbSEtienne Carriere #ifndef CFG_DRIVERS_PINCTRL 7534b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node, 7544b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 7554b5e93edSEtienne Carriere { 75610bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 75710bcbd6cSEtienne Carriere int lenp = 0; 75810bcbd6cSEtienne Carriere int i = 0; 7594b5e93edSEtienne Carriere size_t found = 0; 7604b5e93edSEtienne Carriere 7614b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp); 7624b5e93edSEtienne Carriere if (!cuint) 7634b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7644b5e93edSEtienne Carriere 7654b5e93edSEtienne Carriere for (i = 0; i < (lenp / 4); i++) { 76610bcbd6cSEtienne Carriere int node = 0; 76710bcbd6cSEtienne Carriere int subnode = 0; 7684b5e93edSEtienne Carriere 7694b5e93edSEtienne Carriere node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 7704b5e93edSEtienne Carriere if (node < 0) 7714b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7724b5e93edSEtienne Carriere 7734b5e93edSEtienne Carriere fdt_for_each_subnode(subnode, fdt, node) { 77410bcbd6cSEtienne Carriere size_t n = 0; 77510bcbd6cSEtienne Carriere int rc = 0; 7764b5e93edSEtienne Carriere 7774b5e93edSEtienne Carriere if (count > found) 7784b5e93edSEtienne Carriere n = count - found; 7794b5e93edSEtienne Carriere else 7804b5e93edSEtienne Carriere n = 0; 7814b5e93edSEtienne Carriere 7824b5e93edSEtienne Carriere rc = get_pinctrl_from_fdt(fdt, subnode, 7834b5e93edSEtienne Carriere &pinctrl[found], n); 7844b5e93edSEtienne Carriere if (rc < 0) 7854b5e93edSEtienne Carriere return rc; 7864b5e93edSEtienne Carriere 7874b5e93edSEtienne Carriere found += (size_t)rc; 7884b5e93edSEtienne Carriere } 7894b5e93edSEtienne Carriere 7904b5e93edSEtienne Carriere cuint++; 7914b5e93edSEtienne Carriere } 7924b5e93edSEtienne Carriere 7934b5e93edSEtienne Carriere return (int)found; 7944b5e93edSEtienne Carriere } 795b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 796a3104caaSEtienne Carriere 797a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank) 798a3104caaSEtienne Carriere { 799a3104caaSEtienne Carriere int node = 0; 800a3104caaSEtienne Carriere const fdt32_t *cuint = NULL; 801a3104caaSEtienne Carriere 802a3104caaSEtienne Carriere fdt_for_each_subnode(node, fdt, pinctrl_node) { 803a3104caaSEtienne Carriere if (!fdt_getprop(fdt, node, "gpio-controller", NULL)) 804a3104caaSEtienne Carriere continue; 805a3104caaSEtienne Carriere 806a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "reg", NULL); 807a3104caaSEtienne Carriere if (!cuint) 808a3104caaSEtienne Carriere continue; 809a3104caaSEtienne Carriere 810a3104caaSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 811a3104caaSEtienne Carriere continue; 812a3104caaSEtienne Carriere 813a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "ngpios", NULL); 814a3104caaSEtienne Carriere if (!cuint) 815a3104caaSEtienne Carriere panic(); 816a3104caaSEtienne Carriere 817a3104caaSEtienne Carriere return (int)fdt32_to_cpu(*cuint); 818a3104caaSEtienne Carriere } 819a3104caaSEtienne Carriere 820a3104caaSEtienne Carriere return -1; 821a3104caaSEtienne Carriere } 8224b5e93edSEtienne Carriere 823077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 824077d486eSEtienne Carriere bool secure) 8254b5e93edSEtienne Carriere { 826077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 82798dfcedaSEtienne Carriere uint32_t exceptions = 0; 8284b5e93edSEtienne Carriere 829077d486eSEtienne Carriere if (clk_enable(bank->clock)) 830077d486eSEtienne Carriere panic(); 83198dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 8324b5e93edSEtienne Carriere 8334b5e93edSEtienne Carriere if (secure) 834077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 8354b5e93edSEtienne Carriere else 836077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 8374b5e93edSEtienne Carriere 838c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 83998dfcedaSEtienne Carriere clk_disable(bank->clock); 8404b5e93edSEtienne Carriere } 8410e0435e2SEtienne Carriere 842b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 843b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf) 844b38386fbSEtienne Carriere { 845b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv; 846b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl; 847b38386fbSEtienne Carriere size_t pin_count = ref->count; 848b38386fbSEtienne Carriere size_t n = 0; 849b38386fbSEtienne Carriere 850b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++) 851b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg); 852b38386fbSEtienne Carriere 853b38386fbSEtienne Carriere return TEE_SUCCESS; 854b38386fbSEtienne Carriere } 855b38386fbSEtienne Carriere 856b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf) 857b38386fbSEtienne Carriere { 858b38386fbSEtienne Carriere free(conf); 859b38386fbSEtienne Carriere } 860b38386fbSEtienne Carriere 861b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = { 862b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply, 863b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free, 864b38386fbSEtienne Carriere }; 865b38386fbSEtienne Carriere 866b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops); 867b38386fbSEtienne Carriere 86870ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl, 86970ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin, 87070ac0db5SEtienne Carriere unsigned int *count) 87170ac0db5SEtienne Carriere { 87270ac0db5SEtienne Carriere size_t conf_index = 0; 87370ac0db5SEtienne Carriere size_t pin_count = 0; 87470ac0db5SEtienne Carriere size_t n = 0; 87570ac0db5SEtienne Carriere 87670ac0db5SEtienne Carriere assert(count); 87770ac0db5SEtienne Carriere if (!pinctrl) 87870ac0db5SEtienne Carriere goto out; 87970ac0db5SEtienne Carriere 88070ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 88170ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 88270ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 88370ac0db5SEtienne Carriere 88470ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */ 88570ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 88670ac0db5SEtienne Carriere continue; 88770ac0db5SEtienne Carriere 88870ac0db5SEtienne Carriere if (bank || pin) { 88970ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) { 89070ac0db5SEtienne Carriere if (bank && pin_count < *count) 89170ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank; 89270ac0db5SEtienne Carriere if (pin && pin_count < *count) 89370ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin; 89470ac0db5SEtienne Carriere pin_count++; 89570ac0db5SEtienne Carriere } 89670ac0db5SEtienne Carriere } else { 89770ac0db5SEtienne Carriere pin_count += ref->count; 89870ac0db5SEtienne Carriere } 89970ac0db5SEtienne Carriere } 90070ac0db5SEtienne Carriere 90170ac0db5SEtienne Carriere out: 90270ac0db5SEtienne Carriere *count = pin_count; 90370ac0db5SEtienne Carriere } 90470ac0db5SEtienne Carriere 905*7f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure) 906*7f823a77SEtienne Carriere { 907*7f823a77SEtienne Carriere size_t conf_index = 0; 908*7f823a77SEtienne Carriere 909*7f823a77SEtienne Carriere if (!pinctrl) 910*7f823a77SEtienne Carriere return; 911*7f823a77SEtienne Carriere 912*7f823a77SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) { 913*7f823a77SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index]; 914*7f823a77SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv; 915*7f823a77SEtienne Carriere struct stm32_pinctrl *pc = NULL; 916*7f823a77SEtienne Carriere size_t n = 0; 917*7f823a77SEtienne Carriere 918*7f823a77SEtienne Carriere for (n = 0; n < ref->count; n++) { 919*7f823a77SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops) 920*7f823a77SEtienne Carriere continue; 921*7f823a77SEtienne Carriere 922*7f823a77SEtienne Carriere pc = ref->pinctrl + n; 923*7f823a77SEtienne Carriere stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure); 924*7f823a77SEtienne Carriere } 925*7f823a77SEtienne Carriere } 926*7f823a77SEtienne Carriere } 927*7f823a77SEtienne Carriere 928b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */ 929b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs, 930b38386fbSEtienne Carriere void *data __unused, 931b38386fbSEtienne Carriere struct pinconf **out_pinconf) 932b38386fbSEtienne Carriere { 933b38386fbSEtienne Carriere struct conf { 934b38386fbSEtienne Carriere struct pinconf pinconf; 935b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref; 936b38386fbSEtienne Carriere } *loc_conf = NULL; 937b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL; 938b38386fbSEtienne Carriere struct pinconf *pinconf = NULL; 939b38386fbSEtienne Carriere const void *fdt = NULL; 940b38386fbSEtienne Carriere size_t pin_count = 0; 941b38386fbSEtienne Carriere int pinctrl_node = 0; 942b38386fbSEtienne Carriere int pinmux_node = 0; 943b38386fbSEtienne Carriere int count = 0; 944b38386fbSEtienne Carriere 945b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node; 946b38386fbSEtienne Carriere fdt = pargs->fdt; 947b38386fbSEtienne Carriere assert(fdt && pinctrl_node); 948b38386fbSEtienne Carriere 949b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 950b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count)) 951b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t); 952b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND) 953b38386fbSEtienne Carriere panic(); 954b38386fbSEtienne Carriere } 955b38386fbSEtienne Carriere 956b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count); 957b38386fbSEtienne Carriere if (!loc_conf) 958b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 959b38386fbSEtienne Carriere 960b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf; 961b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops; 962b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref; 963b38386fbSEtienne Carriere 964b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count; 965b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl; 966b38386fbSEtienne Carriere 967b38386fbSEtienne Carriere count = 0; 968b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) { 969b38386fbSEtienne Carriere int found = 0; 970b38386fbSEtienne Carriere 971b38386fbSEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count, 972b38386fbSEtienne Carriere pin_count - count); 973b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) { 974b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */ 975b38386fbSEtienne Carriere panic(); 976b38386fbSEtienne Carriere } 977b38386fbSEtienne Carriere 978b38386fbSEtienne Carriere count += found; 979b38386fbSEtienne Carriere } 980b38386fbSEtienne Carriere 981b38386fbSEtienne Carriere *out_pinconf = pinconf; 982b38386fbSEtienne Carriere 983b38386fbSEtienne Carriere return TEE_SUCCESS; 984b38386fbSEtienne Carriere } 985b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/ 986b38386fbSEtienne Carriere 9870e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 9880e0435e2SEtienne Carriere const void *compat_data) 9890e0435e2SEtienne Carriere { 990b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 991b38386fbSEtienne Carriere 9920e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 993b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data); 994b38386fbSEtienne Carriere if (res) 995b38386fbSEtienne Carriere return res; 996b38386fbSEtienne Carriere 997b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL 998b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get, 999b38386fbSEtienne Carriere (void *)compat_data); 1000b38386fbSEtienne Carriere if (res) 1001b38386fbSEtienne Carriere return res; 1002b38386fbSEtienne Carriere #endif 1003b38386fbSEtienne Carriere 1004b38386fbSEtienne Carriere return TEE_SUCCESS; 10050e0435e2SEtienne Carriere } 10060e0435e2SEtienne Carriere 10070e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 10080e0435e2SEtienne Carriere { .compatible = "st,stm32mp135-pinctrl" }, 10090e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-pinctrl" }, 10100e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-z-pinctrl" }, 10110e0435e2SEtienne Carriere { } 10120e0435e2SEtienne Carriere }; 10130e0435e2SEtienne Carriere 10140e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 10150e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 10160e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 10170e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 10180e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 10190e0435e2SEtienne Carriere }; 1020