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 * The driver API is defined in header file stm32_gpio.h. 74b5e93edSEtienne Carriere */ 84b5e93edSEtienne Carriere 94b5e93edSEtienne Carriere #include <assert.h> 1097391ffbSEtienne Carriere #include <drivers/clk.h> 1197391ffbSEtienne Carriere #include <drivers/clk_dt.h> 12*420a32c5SEtienne Carriere #include <drivers/gpio.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 274b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 284b5e93edSEtienne Carriere 294b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET 0x00 304b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET 0x04 314b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET 0x08 324b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET 0x0c 334b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET 0x10 344b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET 0x14 354b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET 0x18 364b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET 0x20 374b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET 0x24 384b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET 0x30 394b5e93edSEtienne Carriere 404b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT 0x8 414b5e93edSEtienne Carriere 424b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 434b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 444b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 45729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 464b5e93edSEtienne Carriere 474b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT 12 484b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 494b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT 8 504b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 514b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 524b5e93edSEtienne Carriere 539818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 549818a481SEtienne Carriere 559818a481SEtienne Carriere /** 569818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 579818a481SEtienne Carriere * 589818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 599818a481SEtienne Carriere * @clock: clock identifier. 60*420a32c5SEtienne Carriere * @gpio_chip: GPIO chip reference for that GPIO bank 619818a481SEtienne Carriere * @ngpios: number of GPIOs. 629818a481SEtienne Carriere * @bank_id: Id of the bank. 639818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 649818a481SEtienne Carriere * @sec_support: True if bank supports pin security protection, otherwise false 659818a481SEtienne Carriere * @seccfgr: Secure configuration register value. 669818a481SEtienne Carriere * @link: Link in bank list 679818a481SEtienne Carriere */ 689818a481SEtienne Carriere struct stm32_gpio_bank { 699818a481SEtienne Carriere vaddr_t base; 709818a481SEtienne Carriere struct clk *clock; 71*420a32c5SEtienne Carriere struct gpio_chip gpio_chip; 729818a481SEtienne Carriere unsigned int ngpios; 739818a481SEtienne Carriere unsigned int bank_id; 749818a481SEtienne Carriere unsigned int lock; 759818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 769818a481SEtienne Carriere }; 779818a481SEtienne Carriere 784b5e93edSEtienne Carriere static unsigned int gpio_lock; 794b5e93edSEtienne Carriere 809818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 819818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 829818a481SEtienne Carriere 83*420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip); 84*420a32c5SEtienne Carriere 85*420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip) 86*420a32c5SEtienne Carriere { 87*420a32c5SEtienne Carriere return container_of(chip, struct stm32_gpio_bank, gpio_chip); 88*420a32c5SEtienne Carriere } 89*420a32c5SEtienne Carriere 90*420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip, 91*420a32c5SEtienne Carriere unsigned int gpio_pin) 92*420a32c5SEtienne Carriere { 93*420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 94*420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH; 95*420a32c5SEtienne Carriere unsigned int reg_offset = 0; 96*420a32c5SEtienne Carriere unsigned int mode = 0; 97*420a32c5SEtienne Carriere 98*420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 99*420a32c5SEtienne Carriere clk_enable(bank->clock); 100*420a32c5SEtienne Carriere 101*420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 102*420a32c5SEtienne Carriere GPIO_MODE_MASK; 103*420a32c5SEtienne Carriere 104*420a32c5SEtienne Carriere switch (mode) { 105*420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 106*420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET; 107*420a32c5SEtienne Carriere break; 108*420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 109*420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET; 110*420a32c5SEtienne Carriere break; 111*420a32c5SEtienne Carriere default: 112*420a32c5SEtienne Carriere panic(); 113*420a32c5SEtienne Carriere } 114*420a32c5SEtienne Carriere 115*420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin)) 116*420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH; 117*420a32c5SEtienne Carriere else 118*420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW; 119*420a32c5SEtienne Carriere 120*420a32c5SEtienne Carriere clk_disable(bank->clock); 121*420a32c5SEtienne Carriere 122*420a32c5SEtienne Carriere return level; 123*420a32c5SEtienne Carriere } 124*420a32c5SEtienne Carriere 125*420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin, 126*420a32c5SEtienne Carriere enum gpio_level level) 127*420a32c5SEtienne Carriere { 128*420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 129*420a32c5SEtienne Carriere 130*420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 131*420a32c5SEtienne Carriere clk_enable(bank->clock); 132*420a32c5SEtienne Carriere 133*420a32c5SEtienne Carriere assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >> 134*420a32c5SEtienne Carriere (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT); 135*420a32c5SEtienne Carriere 136*420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH) 137*420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin)); 138*420a32c5SEtienne Carriere else 139*420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16)); 140*420a32c5SEtienne Carriere 141*420a32c5SEtienne Carriere clk_disable(bank->clock); 142*420a32c5SEtienne Carriere } 143*420a32c5SEtienne Carriere 144*420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip, 145*420a32c5SEtienne Carriere unsigned int gpio_pin) 146*420a32c5SEtienne Carriere { 147*420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 148*420a32c5SEtienne Carriere uint32_t mode = 0; 149*420a32c5SEtienne Carriere 150*420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 151*420a32c5SEtienne Carriere clk_enable(bank->clock); 152*420a32c5SEtienne Carriere 153*420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) & 154*420a32c5SEtienne Carriere GPIO_MODE_MASK; 155*420a32c5SEtienne Carriere 156*420a32c5SEtienne Carriere clk_disable(bank->clock); 157*420a32c5SEtienne Carriere 158*420a32c5SEtienne Carriere switch (mode) { 159*420a32c5SEtienne Carriere case GPIO_MODE_INPUT: 160*420a32c5SEtienne Carriere return GPIO_DIR_IN; 161*420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT: 162*420a32c5SEtienne Carriere return GPIO_DIR_OUT; 163*420a32c5SEtienne Carriere default: 164*420a32c5SEtienne Carriere panic(); 165*420a32c5SEtienne Carriere } 166*420a32c5SEtienne Carriere } 167*420a32c5SEtienne Carriere 168*420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip, 169*420a32c5SEtienne Carriere unsigned int gpio_pin, 170*420a32c5SEtienne Carriere enum gpio_dir direction) 171*420a32c5SEtienne Carriere { 172*420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip); 173*420a32c5SEtienne Carriere uint32_t exceptions = 0; 174*420a32c5SEtienne Carriere uint32_t mode = 0; 175*420a32c5SEtienne Carriere 176*420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios); 177*420a32c5SEtienne Carriere 178*420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN) 179*420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT; 180*420a32c5SEtienne Carriere else 181*420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT; 182*420a32c5SEtienne Carriere 183*420a32c5SEtienne Carriere clk_enable(bank->clock); 184*420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 185*420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 186*420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1), 187*420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1)); 188*420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 189*420a32c5SEtienne Carriere clk_disable(bank->clock); 190*420a32c5SEtienne Carriere } 191*420a32c5SEtienne Carriere 192*420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused, 193*420a32c5SEtienne Carriere struct gpio *gpio) 194*420a32c5SEtienne Carriere { 195*420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip)); 196*420a32c5SEtienne Carriere free(gpio); 197*420a32c5SEtienne Carriere } 198*420a32c5SEtienne Carriere 199*420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = { 200*420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction, 201*420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction, 202*420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level, 203*420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level, 204*420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio, 205*420a32c5SEtienne Carriere }; 206*420a32c5SEtienne Carriere 207*420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip) 208*420a32c5SEtienne Carriere { 209*420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops; 210*420a32c5SEtienne Carriere } 211*420a32c5SEtienne Carriere 212077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 2134b5e93edSEtienne Carriere { 214077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 2154b5e93edSEtienne Carriere 216077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 217077d486eSEtienne Carriere if (bank_id == bank->bank_id) 218077d486eSEtienne Carriere return bank; 219077d486eSEtienne Carriere 220077d486eSEtienne Carriere panic(); 221077d486eSEtienne Carriere } 222077d486eSEtienne Carriere 223077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 224077d486eSEtienne Carriere static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 225077d486eSEtienne Carriere { 226077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 227077d486eSEtienne Carriere 228077d486eSEtienne Carriere if (clk_enable(bank->clock)) 229077d486eSEtienne Carriere panic(); 2304b5e93edSEtienne Carriere 2314b5e93edSEtienne Carriere /* 2324b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 2334b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 2344b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 2354b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 2364b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 2374b5e93edSEtienne Carriere */ 238077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 2394b5e93edSEtienne Carriere GPIO_MODE_MASK; 2404b5e93edSEtienne Carriere 241077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 2424b5e93edSEtienne Carriere 243077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 244077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 2454b5e93edSEtienne Carriere 246077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 2474b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 2484b5e93edSEtienne Carriere 249077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 2504b5e93edSEtienne Carriere 2514b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 252077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 253077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 2544b5e93edSEtienne Carriere else 255077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 2564b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 2574b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 2584b5e93edSEtienne Carriere 259077d486eSEtienne Carriere clk_disable(bank->clock); 2604b5e93edSEtienne Carriere } 2614b5e93edSEtienne Carriere 2624b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 263077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 2644b5e93edSEtienne Carriere { 265077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 26698dfcedaSEtienne Carriere uint32_t exceptions = 0; 2674b5e93edSEtienne Carriere 268077d486eSEtienne Carriere if (clk_enable(bank->clock)) 269077d486eSEtienne Carriere panic(); 27098dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 2714b5e93edSEtienne Carriere 2724b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 273077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 274bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 275bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 2764b5e93edSEtienne Carriere 2774b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 278077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 279bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 2804b5e93edSEtienne Carriere 2814b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 282077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 283bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 284bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 2854b5e93edSEtienne Carriere 2864b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 287077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 288bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 2894b5e93edSEtienne Carriere 2904b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 2914b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 292077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 293bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 294bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 2954b5e93edSEtienne Carriere } else { 2964b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 2974b5e93edSEtienne Carriere 298077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 299bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 300bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 3014b5e93edSEtienne Carriere } 3024b5e93edSEtienne Carriere 3034b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 304077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 3054b5e93edSEtienne Carriere 306c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 30798dfcedaSEtienne Carriere clk_disable(bank->clock); 3084b5e93edSEtienne Carriere } 3094b5e93edSEtienne Carriere 3104b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3114b5e93edSEtienne Carriere { 31210bcbd6cSEtienne Carriere size_t n = 0; 3134b5e93edSEtienne Carriere 3144b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3154b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3164b5e93edSEtienne Carriere &pinctrl[n].active_cfg); 3174b5e93edSEtienne Carriere } 3184b5e93edSEtienne Carriere 3194b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3204b5e93edSEtienne Carriere { 32110bcbd6cSEtienne Carriere size_t n = 0; 3224b5e93edSEtienne Carriere 3234b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3244b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3254b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3264b5e93edSEtienne Carriere } 3274b5e93edSEtienne Carriere 3284b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 3294b5e93edSEtienne Carriere { 33010bcbd6cSEtienne Carriere size_t n = 0; 3314b5e93edSEtienne Carriere 3324b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 3334b5e93edSEtienne Carriere get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 3344b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 3354b5e93edSEtienne Carriere } 3364b5e93edSEtienne Carriere 33742f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */ 3384b5e93edSEtienne Carriere static void ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) 3394b5e93edSEtienne Carriere { 34010bcbd6cSEtienne Carriere int pinctrl_subnode = 0; 3414b5e93edSEtienne Carriere 3424b5e93edSEtienne Carriere fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { 34310bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 3444b5e93edSEtienne Carriere 3454b5e93edSEtienne Carriere if (fdt_getprop(fdt, pinctrl_subnode, 3464b5e93edSEtienne Carriere "gpio-controller", NULL) == NULL) 3474b5e93edSEtienne Carriere continue; 3484b5e93edSEtienne Carriere 3494b5e93edSEtienne Carriere /* Check bank register offset matches platform assumptions */ 3504b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); 3514b5e93edSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 352563f6249SEtienne Carriere continue; 3534b5e93edSEtienne Carriere 3544b5e93edSEtienne Carriere /* Check controller is enabled */ 355f354a5d8SGatien Chevallier if (fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED) 3564b5e93edSEtienne Carriere panic(); 3574b5e93edSEtienne Carriere 3584b5e93edSEtienne Carriere return; 3594b5e93edSEtienne Carriere } 3604b5e93edSEtienne Carriere 3614b5e93edSEtienne Carriere panic(); 3624b5e93edSEtienne Carriere } 3634b5e93edSEtienne Carriere 3644b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 3654b5e93edSEtienne Carriere static int get_pinctrl_from_fdt(void *fdt, int node, 3664b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 3674b5e93edSEtienne Carriere { 3684b5e93edSEtienne Carriere const fdt32_t *cuint, *slewrate; 36910bcbd6cSEtienne Carriere int len = 0; 37010bcbd6cSEtienne Carriere int pinctrl_node = 0; 37110bcbd6cSEtienne Carriere uint32_t i = 0; 3724b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 3734b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 3744b5e93edSEtienne Carriere size_t found = 0; 3754b5e93edSEtienne Carriere 3764b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 3774b5e93edSEtienne Carriere if (!cuint) 3784b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3794b5e93edSEtienne Carriere 3804b5e93edSEtienne Carriere pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); 3814b5e93edSEtienne Carriere if (pinctrl_node < 0) 3824b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 3834b5e93edSEtienne Carriere 3844b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 3854b5e93edSEtienne Carriere if (slewrate) 3864b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 3874b5e93edSEtienne Carriere 3884b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 3894b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 3904b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 3914b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 3924b5e93edSEtienne Carriere 3934b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 39410bcbd6cSEtienne Carriere uint32_t pincfg = 0; 39510bcbd6cSEtienne Carriere uint32_t bank = 0; 39610bcbd6cSEtienne Carriere uint32_t pin = 0; 39710bcbd6cSEtienne Carriere uint32_t mode = 0; 3984b5e93edSEtienne Carriere uint32_t alternate = 0; 399322cf9e3SEtienne Carriere uint32_t odata = 0; 4004b5e93edSEtienne Carriere bool opendrain = false; 4014b5e93edSEtienne Carriere 4024b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 4034b5e93edSEtienne Carriere cuint++; 4044b5e93edSEtienne Carriere 4054b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 4064b5e93edSEtienne Carriere 4074b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 4084b5e93edSEtienne Carriere 4094b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 4104b5e93edSEtienne Carriere 4114b5e93edSEtienne Carriere switch (mode) { 4124b5e93edSEtienne Carriere case 0: 4134b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 4144b5e93edSEtienne Carriere break; 4154b5e93edSEtienne Carriere case 1: 4164b5e93edSEtienne Carriere case 2: 4174b5e93edSEtienne Carriere case 3: 4184b5e93edSEtienne Carriere case 4: 4194b5e93edSEtienne Carriere case 5: 4204b5e93edSEtienne Carriere case 6: 4214b5e93edSEtienne Carriere case 7: 4224b5e93edSEtienne Carriere case 8: 4234b5e93edSEtienne Carriere case 9: 4244b5e93edSEtienne Carriere case 10: 4254b5e93edSEtienne Carriere case 11: 4264b5e93edSEtienne Carriere case 12: 4274b5e93edSEtienne Carriere case 13: 4284b5e93edSEtienne Carriere case 14: 4294b5e93edSEtienne Carriere case 15: 4304b5e93edSEtienne Carriere case 16: 4314b5e93edSEtienne Carriere alternate = mode - 1U; 4324b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 4334b5e93edSEtienne Carriere break; 4344b5e93edSEtienne Carriere case 17: 4354b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 4364b5e93edSEtienne Carriere break; 4374b5e93edSEtienne Carriere default: 4384b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 4394b5e93edSEtienne Carriere break; 4404b5e93edSEtienne Carriere } 4414b5e93edSEtienne Carriere 4424b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 4434b5e93edSEtienne Carriere opendrain = true; 4444b5e93edSEtienne Carriere 445322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 446322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 447322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 448322cf9e3SEtienne Carriere odata = 1; 449322cf9e3SEtienne Carriere } 450322cf9e3SEtienne Carriere 451322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 452322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 453322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 454322cf9e3SEtienne Carriere odata = 0; 455322cf9e3SEtienne Carriere } 456322cf9e3SEtienne Carriere 4574b5e93edSEtienne Carriere /* Check GPIO bank clock/base address against platform */ 4584b5e93edSEtienne Carriere ckeck_gpio_bank(fdt, bank, pinctrl_node); 4594b5e93edSEtienne Carriere 4604b5e93edSEtienne Carriere if (found < count) { 4614b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 4624b5e93edSEtienne Carriere 4634b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 4644b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 4654b5e93edSEtienne Carriere ref->active_cfg.mode = mode; 4664b5e93edSEtienne Carriere ref->active_cfg.otype = opendrain ? 1 : 0; 4674b5e93edSEtienne Carriere ref->active_cfg.ospeed = speed; 4684b5e93edSEtienne Carriere ref->active_cfg.pupd = pull; 469322cf9e3SEtienne Carriere ref->active_cfg.od = odata; 4704b5e93edSEtienne Carriere ref->active_cfg.af = alternate; 4714b5e93edSEtienne Carriere /* Default to analog mode for standby state */ 4724b5e93edSEtienne Carriere ref->standby_cfg.mode = GPIO_MODE_ANALOG; 4734b5e93edSEtienne Carriere ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL; 4744b5e93edSEtienne Carriere } 4754b5e93edSEtienne Carriere 4764b5e93edSEtienne Carriere found++; 4774b5e93edSEtienne Carriere } 4784b5e93edSEtienne Carriere 4794b5e93edSEtienne Carriere return (int)found; 4804b5e93edSEtienne Carriere } 4814b5e93edSEtienne Carriere 482*420a32c5SEtienne Carriere static struct gpio *stm32_gpio_get_dt(struct dt_pargs *pargs, 483*420a32c5SEtienne Carriere void *data, TEE_Result *res) 484*420a32c5SEtienne Carriere { 485*420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data; 486*420a32c5SEtienne Carriere struct gpio *gpio = NULL; 487*420a32c5SEtienne Carriere unsigned int shift_1b = 0; 488*420a32c5SEtienne Carriere unsigned int shift_2b = 0; 489*420a32c5SEtienne Carriere uint32_t exceptions = 0; 490*420a32c5SEtienne Carriere uint32_t otype = 0; 491*420a32c5SEtienne Carriere uint32_t pupd = 0; 492*420a32c5SEtienne Carriere uint32_t mode = 0; 493*420a32c5SEtienne Carriere 494*420a32c5SEtienne Carriere gpio = gpio_dt_alloc_pin(pargs, res); 495*420a32c5SEtienne Carriere if (*res) 496*420a32c5SEtienne Carriere return NULL; 497*420a32c5SEtienne Carriere 498*420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) { 499*420a32c5SEtienne Carriere DMSG("Invalid GPIO reference"); 500*420a32c5SEtienne Carriere free(gpio); 501*420a32c5SEtienne Carriere return NULL; 502*420a32c5SEtienne Carriere } 503*420a32c5SEtienne Carriere 504*420a32c5SEtienne Carriere shift_1b = gpio->pin; 505*420a32c5SEtienne Carriere shift_2b = SHIFT_U32(gpio->pin, 1); 506*420a32c5SEtienne Carriere 507*420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_PULL_UP) 508*420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_UP; 509*420a32c5SEtienne Carriere else if (gpio->dt_flags & GPIO_PULL_DOWN) 510*420a32c5SEtienne Carriere pupd = GPIO_PUPD_PULL_DOWN; 511*420a32c5SEtienne Carriere else 512*420a32c5SEtienne Carriere pupd = GPIO_PUPD_NO_PULL; 513*420a32c5SEtienne Carriere 514*420a32c5SEtienne Carriere if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN) 515*420a32c5SEtienne Carriere otype = GPIO_OTYPE_OPEN_DRAIN; 516*420a32c5SEtienne Carriere else 517*420a32c5SEtienne Carriere otype = GPIO_OTYPE_PUSH_PULL; 518*420a32c5SEtienne Carriere 519*420a32c5SEtienne Carriere if (clk_enable(bank->clock)) 520*420a32c5SEtienne Carriere panic(); 521*420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 522*420a32c5SEtienne Carriere 523*420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 524*420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, shift_2b), 525*420a32c5SEtienne Carriere SHIFT_U32(mode, shift_2b)); 526*420a32c5SEtienne Carriere 527*420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, 528*420a32c5SEtienne Carriere SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b), 529*420a32c5SEtienne Carriere SHIFT_U32(otype, shift_1b)); 530*420a32c5SEtienne Carriere 531*420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, 532*420a32c5SEtienne Carriere SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b), 533*420a32c5SEtienne Carriere SHIFT_U32(pupd, shift_2b)); 534*420a32c5SEtienne Carriere 535*420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 536*420a32c5SEtienne Carriere clk_disable(bank->clock); 537*420a32c5SEtienne Carriere 538*420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip; 539*420a32c5SEtienne Carriere 540*420a32c5SEtienne Carriere *res = TEE_SUCCESS; 541*420a32c5SEtienne Carriere 542*420a32c5SEtienne Carriere return gpio; 543*420a32c5SEtienne Carriere } 544*420a32c5SEtienne Carriere 5459818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 5469818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 5479818a481SEtienne Carriere { 5489818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 5499818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5509818a481SEtienne Carriere int len = 0; 5519818a481SEtienne Carriere 5529818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 5539818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 5549818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 5559818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 5569818a481SEtienne Carriere 5579818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 5589818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 5599818a481SEtienne Carriere panic("Wrong st,bank-name property"); 5609818a481SEtienne Carriere 5619818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 5629818a481SEtienne Carriere } 5639818a481SEtienne Carriere 5649818a481SEtienne Carriere /* 5659818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 5669818a481SEtienne Carriere * registered in the GPIO bank link. 5679818a481SEtienne Carriere */ 5689818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 5699818a481SEtienne Carriere { 5709818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 5719818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5729818a481SEtienne Carriere 5739818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 5749818a481SEtienne Carriere if (bank->bank_id == bank_id) 5759818a481SEtienne Carriere return true; 5769818a481SEtienne Carriere 5779818a481SEtienne Carriere return false; 5789818a481SEtienne Carriere } 5799818a481SEtienne Carriere 5809818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 5819818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 5829818a481SEtienne Carriere const void *compat_data __unused, 5839818a481SEtienne Carriere int range_offset, 5849818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 5859818a481SEtienne Carriere { 5869818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 5879818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 5889818a481SEtienne Carriere const fdt32_t *cuint = NULL; 5899818a481SEtienne Carriere struct io_pa_va pa_va = { }; 5909818a481SEtienne Carriere struct clk *clk = NULL; 5919818a481SEtienne Carriere size_t blen = 0; 5929818a481SEtienne Carriere paddr_t pa = 0; 5939818a481SEtienne Carriere int len = 0; 5949818a481SEtienne Carriere int i = 0; 5959818a481SEtienne Carriere 5969818a481SEtienne Carriere assert(out_bank); 5979818a481SEtienne Carriere 5989818a481SEtienne Carriere /* Probe deferrable devices first */ 5999818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 6009818a481SEtienne Carriere if (res) 6019818a481SEtienne Carriere return res; 6029818a481SEtienne Carriere 6039818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 6049818a481SEtienne Carriere if (!bank) 6059818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 6069818a481SEtienne Carriere 6079818a481SEtienne Carriere /* 6089818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 6099818a481SEtienne Carriere * but consider also the "ranges" translation property 6109818a481SEtienne Carriere */ 6119818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 6129818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 6139818a481SEtienne Carriere panic("missing reg property"); 6149818a481SEtienne Carriere 6159818a481SEtienne Carriere pa_va.pa = pa + range_offset; 6169818a481SEtienne Carriere 6179818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 6189818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 6199818a481SEtienne Carriere panic("missing reg size property"); 6209818a481SEtienne Carriere 6219818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 6229818a481SEtienne Carriere bank->base = io_pa_or_va_secure(&pa_va, blen); 6239818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 6249818a481SEtienne Carriere bank->clock = clk; 625*420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops; 6269818a481SEtienne Carriere 6279818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 6289818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 6299818a481SEtienne Carriere len /= sizeof(*cuint); 6309818a481SEtienne Carriere if (len % 4) 6319818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 6329818a481SEtienne Carriere 6339818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 6349818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 6359818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 6369818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 6379818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 6389818a481SEtienne Carriere cuint += 4; 6399818a481SEtienne Carriere } 6409818a481SEtienne Carriere 6419818a481SEtienne Carriere *out_bank = bank; 6429818a481SEtienne Carriere return TEE_SUCCESS; 6439818a481SEtienne Carriere } 6449818a481SEtienne Carriere 6459818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */ 6460e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 6479818a481SEtienne Carriere const void *compat_data) 6489818a481SEtienne Carriere { 6499818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 6509818a481SEtienne Carriere const fdt32_t *cuint = NULL; 6519818a481SEtienne Carriere int range_offs = 0; 6529818a481SEtienne Carriere int b_node = 0; 6539818a481SEtienne Carriere int len = 0; 6549818a481SEtienne Carriere 6559818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 6569818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 6579818a481SEtienne Carriere if (!cuint) 6589818a481SEtienne Carriere panic("missing ranges property"); 6599818a481SEtienne Carriere 6609818a481SEtienne Carriere len /= sizeof(*cuint); 6619818a481SEtienne Carriere if (len == 3) 6629818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 6639818a481SEtienne Carriere 6649818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 6659818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 6669818a481SEtienne Carriere if (cuint) { 6679818a481SEtienne Carriere /* 6689818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 6699818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 6709818a481SEtienne Carriere * bank list. 6719818a481SEtienne Carriere */ 6729818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 6739818a481SEtienne Carriere 6749818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 6759818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 6769818a481SEtienne Carriere continue; 6779818a481SEtienne Carriere 6789818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 6799818a481SEtienne Carriere range_offs, &bank); 6809818a481SEtienne Carriere if (res) 6819818a481SEtienne Carriere return res; 6829818a481SEtienne Carriere 683*420a32c5SEtienne Carriere /* Registering a provider should not defer probe */ 684*420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node, 685*420a32c5SEtienne Carriere stm32_gpio_get_dt, bank); 686*420a32c5SEtienne Carriere if (res) 687*420a32c5SEtienne Carriere panic(); 688*420a32c5SEtienne Carriere 6899818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 6909818a481SEtienne Carriere } else { 6919818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 6929818a481SEtienne Carriere panic(); 6939818a481SEtienne Carriere } 6949818a481SEtienne Carriere } 6959818a481SEtienne Carriere 6969818a481SEtienne Carriere return TEE_SUCCESS; 6979818a481SEtienne Carriere } 6989818a481SEtienne Carriere 6994b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node, 7004b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 7014b5e93edSEtienne Carriere { 70210bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 70310bcbd6cSEtienne Carriere int lenp = 0; 70410bcbd6cSEtienne Carriere int i = 0; 7054b5e93edSEtienne Carriere size_t found = 0; 7064b5e93edSEtienne Carriere 7074b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp); 7084b5e93edSEtienne Carriere if (!cuint) 7094b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7104b5e93edSEtienne Carriere 7114b5e93edSEtienne Carriere for (i = 0; i < (lenp / 4); i++) { 71210bcbd6cSEtienne Carriere int node = 0; 71310bcbd6cSEtienne Carriere int subnode = 0; 7144b5e93edSEtienne Carriere 7154b5e93edSEtienne Carriere node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 7164b5e93edSEtienne Carriere if (node < 0) 7174b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 7184b5e93edSEtienne Carriere 7194b5e93edSEtienne Carriere fdt_for_each_subnode(subnode, fdt, node) { 72010bcbd6cSEtienne Carriere size_t n = 0; 72110bcbd6cSEtienne Carriere int rc = 0; 7224b5e93edSEtienne Carriere 7234b5e93edSEtienne Carriere if (count > found) 7244b5e93edSEtienne Carriere n = count - found; 7254b5e93edSEtienne Carriere else 7264b5e93edSEtienne Carriere n = 0; 7274b5e93edSEtienne Carriere 7284b5e93edSEtienne Carriere rc = get_pinctrl_from_fdt(fdt, subnode, 7294b5e93edSEtienne Carriere &pinctrl[found], n); 7304b5e93edSEtienne Carriere if (rc < 0) 7314b5e93edSEtienne Carriere return rc; 7324b5e93edSEtienne Carriere 7334b5e93edSEtienne Carriere found += (size_t)rc; 7344b5e93edSEtienne Carriere } 7354b5e93edSEtienne Carriere 7364b5e93edSEtienne Carriere cuint++; 7374b5e93edSEtienne Carriere } 7384b5e93edSEtienne Carriere 7394b5e93edSEtienne Carriere return (int)found; 7404b5e93edSEtienne Carriere } 741a3104caaSEtienne Carriere 742a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank) 743a3104caaSEtienne Carriere { 744a3104caaSEtienne Carriere int node = 0; 745a3104caaSEtienne Carriere const fdt32_t *cuint = NULL; 746a3104caaSEtienne Carriere 747a3104caaSEtienne Carriere fdt_for_each_subnode(node, fdt, pinctrl_node) { 748a3104caaSEtienne Carriere if (!fdt_getprop(fdt, node, "gpio-controller", NULL)) 749a3104caaSEtienne Carriere continue; 750a3104caaSEtienne Carriere 751a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "reg", NULL); 752a3104caaSEtienne Carriere if (!cuint) 753a3104caaSEtienne Carriere continue; 754a3104caaSEtienne Carriere 755a3104caaSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 756a3104caaSEtienne Carriere continue; 757a3104caaSEtienne Carriere 758a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "ngpios", NULL); 759a3104caaSEtienne Carriere if (!cuint) 760a3104caaSEtienne Carriere panic(); 761a3104caaSEtienne Carriere 762a3104caaSEtienne Carriere return (int)fdt32_to_cpu(*cuint); 763a3104caaSEtienne Carriere } 764a3104caaSEtienne Carriere 765a3104caaSEtienne Carriere return -1; 766a3104caaSEtienne Carriere } 7674b5e93edSEtienne Carriere 768077d486eSEtienne Carriere static __maybe_unused bool valid_gpio_config(unsigned int bank_id, 7694b5e93edSEtienne Carriere unsigned int pin, bool input) 7704b5e93edSEtienne Carriere { 771077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 772077d486eSEtienne Carriere uint32_t mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> 773077d486eSEtienne Carriere (pin << 1)) & GPIO_MODE_MASK; 7744b5e93edSEtienne Carriere 7754b5e93edSEtienne Carriere if (pin > GPIO_PIN_MAX) 7764b5e93edSEtienne Carriere return false; 7774b5e93edSEtienne Carriere 7784b5e93edSEtienne Carriere if (input) 7794b5e93edSEtienne Carriere return mode == GPIO_MODE_INPUT; 7804b5e93edSEtienne Carriere else 7814b5e93edSEtienne Carriere return mode == GPIO_MODE_OUTPUT; 7824b5e93edSEtienne Carriere } 7834b5e93edSEtienne Carriere 784077d486eSEtienne Carriere int stm32_gpio_get_input_level(unsigned int bank_id, unsigned int pin) 7854b5e93edSEtienne Carriere { 786077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 7874b5e93edSEtienne Carriere int rc = 0; 7884b5e93edSEtienne Carriere 789077d486eSEtienne Carriere if (clk_enable(bank->clock)) 790077d486eSEtienne Carriere panic(); 7914b5e93edSEtienne Carriere 792077d486eSEtienne Carriere assert(valid_gpio_config(bank_id, pin, true)); 7936fdc9662SLoïc Bauer 794077d486eSEtienne Carriere if (io_read32(bank->base + GPIO_IDR_OFFSET) == BIT(pin)) 7954b5e93edSEtienne Carriere rc = 1; 7964b5e93edSEtienne Carriere 797077d486eSEtienne Carriere clk_disable(bank->clock); 7984b5e93edSEtienne Carriere 7994b5e93edSEtienne Carriere return rc; 8004b5e93edSEtienne Carriere } 8014b5e93edSEtienne Carriere 802077d486eSEtienne Carriere void stm32_gpio_set_output_level(unsigned int bank_id, unsigned int pin, 803077d486eSEtienne Carriere int level) 8044b5e93edSEtienne Carriere { 805077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 8064b5e93edSEtienne Carriere 807077d486eSEtienne Carriere if (clk_enable(bank->clock)) 808077d486eSEtienne Carriere panic(); 8094b5e93edSEtienne Carriere 810077d486eSEtienne Carriere assert(valid_gpio_config(bank_id, pin, false)); 8116fdc9662SLoïc Bauer 8124b5e93edSEtienne Carriere if (level) 813077d486eSEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(pin)); 8144b5e93edSEtienne Carriere else 815077d486eSEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(pin + 16)); 8164b5e93edSEtienne Carriere 817077d486eSEtienne Carriere clk_disable(bank->clock); 8184b5e93edSEtienne Carriere } 8194b5e93edSEtienne Carriere 820077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 821077d486eSEtienne Carriere bool secure) 8224b5e93edSEtienne Carriere { 823077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 82498dfcedaSEtienne Carriere uint32_t exceptions = 0; 8254b5e93edSEtienne Carriere 826077d486eSEtienne Carriere if (clk_enable(bank->clock)) 827077d486eSEtienne Carriere panic(); 82898dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 8294b5e93edSEtienne Carriere 8304b5e93edSEtienne Carriere if (secure) 831077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 8324b5e93edSEtienne Carriere else 833077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 8344b5e93edSEtienne Carriere 835c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 83698dfcedaSEtienne Carriere clk_disable(bank->clock); 8374b5e93edSEtienne Carriere } 8380e0435e2SEtienne Carriere 8390e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 8400e0435e2SEtienne Carriere const void *compat_data) 8410e0435e2SEtienne Carriere { 8420e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 8430e0435e2SEtienne Carriere return dt_stm32_gpio_pinctrl(fdt, node, compat_data); 8440e0435e2SEtienne Carriere } 8450e0435e2SEtienne Carriere 8460e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 8470e0435e2SEtienne Carriere { .compatible = "st,stm32mp135-pinctrl" }, 8480e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-pinctrl" }, 8490e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-z-pinctrl" }, 8500e0435e2SEtienne Carriere { } 8510e0435e2SEtienne Carriere }; 8520e0435e2SEtienne Carriere 8530e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 8540e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 8550e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 8560e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 8570e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 8580e0435e2SEtienne Carriere }; 859