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> 124b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h> 134b5e93edSEtienne Carriere #include <io.h> 144b5e93edSEtienne Carriere #include <kernel/dt.h> 1565401337SJens Wiklander #include <kernel/boot.h> 164b5e93edSEtienne Carriere #include <kernel/panic.h> 174b5e93edSEtienne Carriere #include <kernel/spinlock.h> 18a2fc83d1SJerome Forissier #include <libfdt.h> 194b5e93edSEtienne Carriere #include <mm/core_memprot.h> 204b5e93edSEtienne Carriere #include <stdbool.h> 214b5e93edSEtienne Carriere #include <stm32_util.h> 229818a481SEtienne Carriere #include <sys/queue.h> 234b5e93edSEtienne Carriere #include <trace.h> 244b5e93edSEtienne Carriere #include <util.h> 254b5e93edSEtienne Carriere 264b5e93edSEtienne Carriere #define GPIO_PIN_MAX 15 274b5e93edSEtienne Carriere 284b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET 0x00 294b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET 0x04 304b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET 0x08 314b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET 0x0c 324b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET 0x10 334b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET 0x14 344b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET 0x18 354b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET 0x20 364b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET 0x24 374b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET 0x30 384b5e93edSEtienne Carriere 394b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT 0x8 404b5e93edSEtienne Carriere 414b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0) 424b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0) 434b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0) 44729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0) 454b5e93edSEtienne Carriere 464b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT 12 474b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12) 484b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT 8 494b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8) 504b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0) 514b5e93edSEtienne Carriere 529818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA" 539818a481SEtienne Carriere 549818a481SEtienne Carriere /** 559818a481SEtienne Carriere * struct stm32_gpio_bank - GPIO bank instance 569818a481SEtienne Carriere * 579818a481SEtienne Carriere * @base: base address of the GPIO controller registers. 589818a481SEtienne Carriere * @clock: clock identifier. 599818a481SEtienne Carriere * @ngpios: number of GPIOs. 609818a481SEtienne Carriere * @bank_id: Id of the bank. 619818a481SEtienne Carriere * @lock: lock protecting the GPIO bank access. 629818a481SEtienne Carriere * @sec_support: True if bank supports pin security protection, otherwise false 639818a481SEtienne Carriere * @seccfgr: Secure configuration register value. 649818a481SEtienne Carriere * @link: Link in bank list 659818a481SEtienne Carriere */ 669818a481SEtienne Carriere struct stm32_gpio_bank { 679818a481SEtienne Carriere vaddr_t base; 689818a481SEtienne Carriere struct clk *clock; 699818a481SEtienne Carriere unsigned int ngpios; 709818a481SEtienne Carriere unsigned int bank_id; 719818a481SEtienne Carriere unsigned int lock; 729818a481SEtienne Carriere STAILQ_ENTRY(stm32_gpio_bank) link; 739818a481SEtienne Carriere }; 749818a481SEtienne Carriere 754b5e93edSEtienne Carriere static unsigned int gpio_lock; 764b5e93edSEtienne Carriere 779818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list = 789818a481SEtienne Carriere STAILQ_HEAD_INITIALIZER(bank_list); 799818a481SEtienne Carriere 80077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id) 814b5e93edSEtienne Carriere { 82077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL; 834b5e93edSEtienne Carriere 84077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 85077d486eSEtienne Carriere if (bank_id == bank->bank_id) 86077d486eSEtienne Carriere return bank; 87077d486eSEtienne Carriere 88077d486eSEtienne Carriere panic(); 89077d486eSEtienne Carriere } 90077d486eSEtienne Carriere 91077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */ 92077d486eSEtienne Carriere static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 93077d486eSEtienne Carriere { 94077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 95077d486eSEtienne Carriere 96077d486eSEtienne Carriere if (clk_enable(bank->clock)) 97077d486eSEtienne Carriere panic(); 984b5e93edSEtienne Carriere 994b5e93edSEtienne Carriere /* 1004b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers. 1014b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index. 1024b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index. 1034b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index 1044b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses. 1054b5e93edSEtienne Carriere */ 106077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) & 1074b5e93edSEtienne Carriere GPIO_MODE_MASK; 1084b5e93edSEtienne Carriere 109077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1; 1104b5e93edSEtienne Carriere 111077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >> 112077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK; 1134b5e93edSEtienne Carriere 114077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) & 1154b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK; 1164b5e93edSEtienne Carriere 117077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; 1184b5e93edSEtienne Carriere 1194b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) 120077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >> 121077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK; 1224b5e93edSEtienne Carriere else 123077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >> 1244b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & 1254b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK; 1264b5e93edSEtienne Carriere 127077d486eSEtienne Carriere clk_disable(bank->clock); 1284b5e93edSEtienne Carriere } 1294b5e93edSEtienne Carriere 1304b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */ 131077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg) 1324b5e93edSEtienne Carriere { 133077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 134*98dfcedaSEtienne Carriere uint32_t exceptions = 0; 1354b5e93edSEtienne Carriere 136077d486eSEtienne Carriere if (clk_enable(bank->clock)) 137077d486eSEtienne Carriere panic(); 138*98dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 1394b5e93edSEtienne Carriere 1404b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ 141077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET, 142bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1), 143bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1)); 1444b5e93edSEtienne Carriere 1454b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */ 146077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin), 147bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin)); 1484b5e93edSEtienne Carriere 1494b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */ 150077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET, 151bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1), 152bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1)); 1534b5e93edSEtienne Carriere 1544b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */ 155077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin), 156bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1)); 1574b5e93edSEtienne Carriere 1584b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */ 1594b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) { 160077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET, 161bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2), 162bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2)); 1634b5e93edSEtienne Carriere } else { 1644b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; 1654b5e93edSEtienne Carriere 166077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET, 167bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift), 168bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift)); 1694b5e93edSEtienne Carriere } 1704b5e93edSEtienne Carriere 1714b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */ 172077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); 1734b5e93edSEtienne Carriere 174c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 175*98dfcedaSEtienne Carriere clk_disable(bank->clock); 1764b5e93edSEtienne Carriere } 1774b5e93edSEtienne Carriere 1784b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 1794b5e93edSEtienne Carriere { 18010bcbd6cSEtienne Carriere size_t n = 0; 1814b5e93edSEtienne Carriere 1824b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 1834b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 1844b5e93edSEtienne Carriere &pinctrl[n].active_cfg); 1854b5e93edSEtienne Carriere } 1864b5e93edSEtienne Carriere 1874b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 1884b5e93edSEtienne Carriere { 18910bcbd6cSEtienne Carriere size_t n = 0; 1904b5e93edSEtienne Carriere 1914b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 1924b5e93edSEtienne Carriere set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 1934b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 1944b5e93edSEtienne Carriere } 1954b5e93edSEtienne Carriere 1964b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) 1974b5e93edSEtienne Carriere { 19810bcbd6cSEtienne Carriere size_t n = 0; 1994b5e93edSEtienne Carriere 2004b5e93edSEtienne Carriere for (n = 0; n < cnt; n++) 2014b5e93edSEtienne Carriere get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, 2024b5e93edSEtienne Carriere &pinctrl[n].standby_cfg); 2034b5e93edSEtienne Carriere } 2044b5e93edSEtienne Carriere 20542f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */ 2064b5e93edSEtienne Carriere static void ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) 2074b5e93edSEtienne Carriere { 20810bcbd6cSEtienne Carriere int pinctrl_subnode = 0; 2094b5e93edSEtienne Carriere 2104b5e93edSEtienne Carriere fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { 21110bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 2124b5e93edSEtienne Carriere 2134b5e93edSEtienne Carriere if (fdt_getprop(fdt, pinctrl_subnode, 2144b5e93edSEtienne Carriere "gpio-controller", NULL) == NULL) 2154b5e93edSEtienne Carriere continue; 2164b5e93edSEtienne Carriere 2174b5e93edSEtienne Carriere /* Check bank register offset matches platform assumptions */ 2184b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); 2194b5e93edSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 220563f6249SEtienne Carriere continue; 2214b5e93edSEtienne Carriere 2224b5e93edSEtienne Carriere /* Check controller is enabled */ 223f354a5d8SGatien Chevallier if (fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED) 2244b5e93edSEtienne Carriere panic(); 2254b5e93edSEtienne Carriere 2264b5e93edSEtienne Carriere return; 2274b5e93edSEtienne Carriere } 2284b5e93edSEtienne Carriere 2294b5e93edSEtienne Carriere panic(); 2304b5e93edSEtienne Carriere } 2314b5e93edSEtienne Carriere 2324b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */ 2334b5e93edSEtienne Carriere static int get_pinctrl_from_fdt(void *fdt, int node, 2344b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 2354b5e93edSEtienne Carriere { 2364b5e93edSEtienne Carriere const fdt32_t *cuint, *slewrate; 23710bcbd6cSEtienne Carriere int len = 0; 23810bcbd6cSEtienne Carriere int pinctrl_node = 0; 23910bcbd6cSEtienne Carriere uint32_t i = 0; 2404b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW; 2414b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL; 2424b5e93edSEtienne Carriere size_t found = 0; 2434b5e93edSEtienne Carriere 2444b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len); 2454b5e93edSEtienne Carriere if (!cuint) 2464b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 2474b5e93edSEtienne Carriere 2484b5e93edSEtienne Carriere pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); 2494b5e93edSEtienne Carriere if (pinctrl_node < 0) 2504b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 2514b5e93edSEtienne Carriere 2524b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); 2534b5e93edSEtienne Carriere if (slewrate) 2544b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate); 2554b5e93edSEtienne Carriere 2564b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL)) 2574b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP; 2584b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL)) 2594b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN; 2604b5e93edSEtienne Carriere 2614b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 26210bcbd6cSEtienne Carriere uint32_t pincfg = 0; 26310bcbd6cSEtienne Carriere uint32_t bank = 0; 26410bcbd6cSEtienne Carriere uint32_t pin = 0; 26510bcbd6cSEtienne Carriere uint32_t mode = 0; 2664b5e93edSEtienne Carriere uint32_t alternate = 0; 267322cf9e3SEtienne Carriere uint32_t odata = 0; 2684b5e93edSEtienne Carriere bool opendrain = false; 2694b5e93edSEtienne Carriere 2704b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint); 2714b5e93edSEtienne Carriere cuint++; 2724b5e93edSEtienne Carriere 2734b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; 2744b5e93edSEtienne Carriere 2754b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; 2764b5e93edSEtienne Carriere 2774b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK; 2784b5e93edSEtienne Carriere 2794b5e93edSEtienne Carriere switch (mode) { 2804b5e93edSEtienne Carriere case 0: 2814b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT; 2824b5e93edSEtienne Carriere break; 2834b5e93edSEtienne Carriere case 1: 2844b5e93edSEtienne Carriere case 2: 2854b5e93edSEtienne Carriere case 3: 2864b5e93edSEtienne Carriere case 4: 2874b5e93edSEtienne Carriere case 5: 2884b5e93edSEtienne Carriere case 6: 2894b5e93edSEtienne Carriere case 7: 2904b5e93edSEtienne Carriere case 8: 2914b5e93edSEtienne Carriere case 9: 2924b5e93edSEtienne Carriere case 10: 2934b5e93edSEtienne Carriere case 11: 2944b5e93edSEtienne Carriere case 12: 2954b5e93edSEtienne Carriere case 13: 2964b5e93edSEtienne Carriere case 14: 2974b5e93edSEtienne Carriere case 15: 2984b5e93edSEtienne Carriere case 16: 2994b5e93edSEtienne Carriere alternate = mode - 1U; 3004b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE; 3014b5e93edSEtienne Carriere break; 3024b5e93edSEtienne Carriere case 17: 3034b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG; 3044b5e93edSEtienne Carriere break; 3054b5e93edSEtienne Carriere default: 3064b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT; 3074b5e93edSEtienne Carriere break; 3084b5e93edSEtienne Carriere } 3094b5e93edSEtienne Carriere 3104b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL)) 3114b5e93edSEtienne Carriere opendrain = true; 3124b5e93edSEtienne Carriere 313322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) && 314322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 315322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 316322cf9e3SEtienne Carriere odata = 1; 317322cf9e3SEtienne Carriere } 318322cf9e3SEtienne Carriere 319322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) && 320322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) { 321322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT; 322322cf9e3SEtienne Carriere odata = 0; 323322cf9e3SEtienne Carriere } 324322cf9e3SEtienne Carriere 3254b5e93edSEtienne Carriere /* Check GPIO bank clock/base address against platform */ 3264b5e93edSEtienne Carriere ckeck_gpio_bank(fdt, bank, pinctrl_node); 3274b5e93edSEtienne Carriere 3284b5e93edSEtienne Carriere if (found < count) { 3294b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found]; 3304b5e93edSEtienne Carriere 3314b5e93edSEtienne Carriere ref->bank = (uint8_t)bank; 3324b5e93edSEtienne Carriere ref->pin = (uint8_t)pin; 3334b5e93edSEtienne Carriere ref->active_cfg.mode = mode; 3344b5e93edSEtienne Carriere ref->active_cfg.otype = opendrain ? 1 : 0; 3354b5e93edSEtienne Carriere ref->active_cfg.ospeed = speed; 3364b5e93edSEtienne Carriere ref->active_cfg.pupd = pull; 337322cf9e3SEtienne Carriere ref->active_cfg.od = odata; 3384b5e93edSEtienne Carriere ref->active_cfg.af = alternate; 3394b5e93edSEtienne Carriere /* Default to analog mode for standby state */ 3404b5e93edSEtienne Carriere ref->standby_cfg.mode = GPIO_MODE_ANALOG; 3414b5e93edSEtienne Carriere ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL; 3424b5e93edSEtienne Carriere } 3434b5e93edSEtienne Carriere 3444b5e93edSEtienne Carriere found++; 3454b5e93edSEtienne Carriere } 3464b5e93edSEtienne Carriere 3474b5e93edSEtienne Carriere return (int)found; 3484b5e93edSEtienne Carriere } 3494b5e93edSEtienne Carriere 3509818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */ 3519818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node) 3529818a481SEtienne Carriere { 3539818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0); 3549818a481SEtienne Carriere const fdt32_t *cuint = NULL; 3559818a481SEtienne Carriere int len = 0; 3569818a481SEtienne Carriere 3579818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */ 3589818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len); 3599818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1)) 3609818a481SEtienne Carriere panic("Missing/wrong st,bank-name property"); 3619818a481SEtienne Carriere 3629818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) || 3639818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0) 3649818a481SEtienne Carriere panic("Wrong st,bank-name property"); 3659818a481SEtienne Carriere 3669818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0); 3679818a481SEtienne Carriere } 3689818a481SEtienne Carriere 3699818a481SEtienne Carriere /* 3709818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already 3719818a481SEtienne Carriere * registered in the GPIO bank link. 3729818a481SEtienne Carriere */ 3739818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node) 3749818a481SEtienne Carriere { 3759818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node); 3769818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 3779818a481SEtienne Carriere 3789818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link) 3799818a481SEtienne Carriere if (bank->bank_id == bank_id) 3809818a481SEtienne Carriere return true; 3819818a481SEtienne Carriere 3829818a481SEtienne Carriere return false; 3839818a481SEtienne Carriere } 3849818a481SEtienne Carriere 3859818a481SEtienne Carriere /* Get GPIO bank information from the DT */ 3869818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node, 3879818a481SEtienne Carriere const void *compat_data __unused, 3889818a481SEtienne Carriere int range_offset, 3899818a481SEtienne Carriere struct stm32_gpio_bank **out_bank) 3909818a481SEtienne Carriere { 3919818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 3929818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 3939818a481SEtienne Carriere const fdt32_t *cuint = NULL; 3949818a481SEtienne Carriere struct io_pa_va pa_va = { }; 3959818a481SEtienne Carriere struct clk *clk = NULL; 3969818a481SEtienne Carriere size_t blen = 0; 3979818a481SEtienne Carriere paddr_t pa = 0; 3989818a481SEtienne Carriere int len = 0; 3999818a481SEtienne Carriere int i = 0; 4009818a481SEtienne Carriere 4019818a481SEtienne Carriere assert(out_bank); 4029818a481SEtienne Carriere 4039818a481SEtienne Carriere /* Probe deferrable devices first */ 4049818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk); 4059818a481SEtienne Carriere if (res) 4069818a481SEtienne Carriere return res; 4079818a481SEtienne Carriere 4089818a481SEtienne Carriere bank = calloc(1, sizeof(*bank)); 4099818a481SEtienne Carriere if (!bank) 4109818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 4119818a481SEtienne Carriere 4129818a481SEtienne Carriere /* 4139818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address, 4149818a481SEtienne Carriere * but consider also the "ranges" translation property 4159818a481SEtienne Carriere */ 4169818a481SEtienne Carriere pa = fdt_reg_base_address(fdt, node); 4179818a481SEtienne Carriere if (pa == DT_INFO_INVALID_REG) 4189818a481SEtienne Carriere panic("missing reg property"); 4199818a481SEtienne Carriere 4209818a481SEtienne Carriere pa_va.pa = pa + range_offset; 4219818a481SEtienne Carriere 4229818a481SEtienne Carriere blen = fdt_reg_size(fdt, node); 4239818a481SEtienne Carriere if (blen == DT_INFO_INVALID_REG_SIZE) 4249818a481SEtienne Carriere panic("missing reg size property"); 4259818a481SEtienne Carriere 4269818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL)); 4279818a481SEtienne Carriere bank->base = io_pa_or_va_secure(&pa_va, blen); 4289818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node); 4299818a481SEtienne Carriere bank->clock = clk; 4309818a481SEtienne Carriere 4319818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */ 4329818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 4339818a481SEtienne Carriere len /= sizeof(*cuint); 4349818a481SEtienne Carriere if (len % 4) 4359818a481SEtienne Carriere panic("wrong gpio-ranges syntax"); 4369818a481SEtienne Carriere 4379818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */ 4389818a481SEtienne Carriere for (i = 0; i < len / 4; i++) { 4399818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios, 4409818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) + 4419818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3)))); 4429818a481SEtienne Carriere cuint += 4; 4439818a481SEtienne Carriere } 4449818a481SEtienne Carriere 4459818a481SEtienne Carriere *out_bank = bank; 4469818a481SEtienne Carriere return TEE_SUCCESS; 4479818a481SEtienne Carriere } 4489818a481SEtienne Carriere 4499818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */ 4500e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node, 4519818a481SEtienne Carriere const void *compat_data) 4529818a481SEtienne Carriere { 4539818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS; 4549818a481SEtienne Carriere const fdt32_t *cuint = NULL; 4559818a481SEtienne Carriere int range_offs = 0; 4569818a481SEtienne Carriere int b_node = 0; 4579818a481SEtienne Carriere int len = 0; 4589818a481SEtienne Carriere 4599818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */ 4609818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len); 4619818a481SEtienne Carriere if (!cuint) 4629818a481SEtienne Carriere panic("missing ranges property"); 4639818a481SEtienne Carriere 4649818a481SEtienne Carriere len /= sizeof(*cuint); 4659818a481SEtienne Carriere if (len == 3) 4669818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint); 4679818a481SEtienne Carriere 4689818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) { 4699818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len); 4709818a481SEtienne Carriere if (cuint) { 4719818a481SEtienne Carriere /* 4729818a481SEtienne Carriere * We found a property "gpio-controller" in the node: 4739818a481SEtienne Carriere * the node is a GPIO bank description, add it to the 4749818a481SEtienne Carriere * bank list. 4759818a481SEtienne Carriere */ 4769818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL; 4779818a481SEtienne Carriere 4789818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED || 4799818a481SEtienne Carriere bank_is_registered(fdt, b_node)) 4809818a481SEtienne Carriere continue; 4819818a481SEtienne Carriere 4829818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data, 4839818a481SEtienne Carriere range_offs, &bank); 4849818a481SEtienne Carriere if (res) 4859818a481SEtienne Carriere return res; 4869818a481SEtienne Carriere 4879818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link); 4889818a481SEtienne Carriere } else { 4899818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND) 4909818a481SEtienne Carriere panic(); 4919818a481SEtienne Carriere } 4929818a481SEtienne Carriere } 4939818a481SEtienne Carriere 4949818a481SEtienne Carriere return TEE_SUCCESS; 4959818a481SEtienne Carriere } 4969818a481SEtienne Carriere 4974b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node, 4984b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count) 4994b5e93edSEtienne Carriere { 50010bcbd6cSEtienne Carriere const fdt32_t *cuint = NULL; 50110bcbd6cSEtienne Carriere int lenp = 0; 50210bcbd6cSEtienne Carriere int i = 0; 5034b5e93edSEtienne Carriere size_t found = 0; 5044b5e93edSEtienne Carriere 5054b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp); 5064b5e93edSEtienne Carriere if (!cuint) 5074b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 5084b5e93edSEtienne Carriere 5094b5e93edSEtienne Carriere for (i = 0; i < (lenp / 4); i++) { 51010bcbd6cSEtienne Carriere int node = 0; 51110bcbd6cSEtienne Carriere int subnode = 0; 5124b5e93edSEtienne Carriere 5134b5e93edSEtienne Carriere node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 5144b5e93edSEtienne Carriere if (node < 0) 5154b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND; 5164b5e93edSEtienne Carriere 5174b5e93edSEtienne Carriere fdt_for_each_subnode(subnode, fdt, node) { 51810bcbd6cSEtienne Carriere size_t n = 0; 51910bcbd6cSEtienne Carriere int rc = 0; 5204b5e93edSEtienne Carriere 5214b5e93edSEtienne Carriere if (count > found) 5224b5e93edSEtienne Carriere n = count - found; 5234b5e93edSEtienne Carriere else 5244b5e93edSEtienne Carriere n = 0; 5254b5e93edSEtienne Carriere 5264b5e93edSEtienne Carriere rc = get_pinctrl_from_fdt(fdt, subnode, 5274b5e93edSEtienne Carriere &pinctrl[found], n); 5284b5e93edSEtienne Carriere if (rc < 0) 5294b5e93edSEtienne Carriere return rc; 5304b5e93edSEtienne Carriere 5314b5e93edSEtienne Carriere found += (size_t)rc; 5324b5e93edSEtienne Carriere } 5334b5e93edSEtienne Carriere 5344b5e93edSEtienne Carriere cuint++; 5354b5e93edSEtienne Carriere } 5364b5e93edSEtienne Carriere 5374b5e93edSEtienne Carriere return (int)found; 5384b5e93edSEtienne Carriere } 539a3104caaSEtienne Carriere 540a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank) 541a3104caaSEtienne Carriere { 542a3104caaSEtienne Carriere int node = 0; 543a3104caaSEtienne Carriere const fdt32_t *cuint = NULL; 544a3104caaSEtienne Carriere 545a3104caaSEtienne Carriere fdt_for_each_subnode(node, fdt, pinctrl_node) { 546a3104caaSEtienne Carriere if (!fdt_getprop(fdt, node, "gpio-controller", NULL)) 547a3104caaSEtienne Carriere continue; 548a3104caaSEtienne Carriere 549a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "reg", NULL); 550a3104caaSEtienne Carriere if (!cuint) 551a3104caaSEtienne Carriere continue; 552a3104caaSEtienne Carriere 553a3104caaSEtienne Carriere if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank)) 554a3104caaSEtienne Carriere continue; 555a3104caaSEtienne Carriere 556a3104caaSEtienne Carriere cuint = fdt_getprop(fdt, node, "ngpios", NULL); 557a3104caaSEtienne Carriere if (!cuint) 558a3104caaSEtienne Carriere panic(); 559a3104caaSEtienne Carriere 560a3104caaSEtienne Carriere return (int)fdt32_to_cpu(*cuint); 561a3104caaSEtienne Carriere } 562a3104caaSEtienne Carriere 563a3104caaSEtienne Carriere return -1; 564a3104caaSEtienne Carriere } 5654b5e93edSEtienne Carriere 566077d486eSEtienne Carriere static __maybe_unused bool valid_gpio_config(unsigned int bank_id, 5674b5e93edSEtienne Carriere unsigned int pin, bool input) 5684b5e93edSEtienne Carriere { 569077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 570077d486eSEtienne Carriere uint32_t mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> 571077d486eSEtienne Carriere (pin << 1)) & GPIO_MODE_MASK; 5724b5e93edSEtienne Carriere 5734b5e93edSEtienne Carriere if (pin > GPIO_PIN_MAX) 5744b5e93edSEtienne Carriere return false; 5754b5e93edSEtienne Carriere 5764b5e93edSEtienne Carriere if (input) 5774b5e93edSEtienne Carriere return mode == GPIO_MODE_INPUT; 5784b5e93edSEtienne Carriere else 5794b5e93edSEtienne Carriere return mode == GPIO_MODE_OUTPUT; 5804b5e93edSEtienne Carriere } 5814b5e93edSEtienne Carriere 582077d486eSEtienne Carriere int stm32_gpio_get_input_level(unsigned int bank_id, unsigned int pin) 5834b5e93edSEtienne Carriere { 584077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 5854b5e93edSEtienne Carriere int rc = 0; 5864b5e93edSEtienne Carriere 587077d486eSEtienne Carriere if (clk_enable(bank->clock)) 588077d486eSEtienne Carriere panic(); 5894b5e93edSEtienne Carriere 590077d486eSEtienne Carriere assert(valid_gpio_config(bank_id, pin, true)); 5916fdc9662SLoïc Bauer 592077d486eSEtienne Carriere if (io_read32(bank->base + GPIO_IDR_OFFSET) == BIT(pin)) 5934b5e93edSEtienne Carriere rc = 1; 5944b5e93edSEtienne Carriere 595077d486eSEtienne Carriere clk_disable(bank->clock); 5964b5e93edSEtienne Carriere 5974b5e93edSEtienne Carriere return rc; 5984b5e93edSEtienne Carriere } 5994b5e93edSEtienne Carriere 600077d486eSEtienne Carriere void stm32_gpio_set_output_level(unsigned int bank_id, unsigned int pin, 601077d486eSEtienne Carriere int level) 6024b5e93edSEtienne Carriere { 603077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 6044b5e93edSEtienne Carriere 605077d486eSEtienne Carriere if (clk_enable(bank->clock)) 606077d486eSEtienne Carriere panic(); 6074b5e93edSEtienne Carriere 608077d486eSEtienne Carriere assert(valid_gpio_config(bank_id, pin, false)); 6096fdc9662SLoïc Bauer 6104b5e93edSEtienne Carriere if (level) 611077d486eSEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(pin)); 6124b5e93edSEtienne Carriere else 613077d486eSEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(pin + 16)); 6144b5e93edSEtienne Carriere 615077d486eSEtienne Carriere clk_disable(bank->clock); 6164b5e93edSEtienne Carriere } 6174b5e93edSEtienne Carriere 618077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin, 619077d486eSEtienne Carriere bool secure) 6204b5e93edSEtienne Carriere { 621077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id); 622*98dfcedaSEtienne Carriere uint32_t exceptions = 0; 6234b5e93edSEtienne Carriere 624077d486eSEtienne Carriere if (clk_enable(bank->clock)) 625077d486eSEtienne Carriere panic(); 626*98dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock); 6274b5e93edSEtienne Carriere 6284b5e93edSEtienne Carriere if (secure) 629077d486eSEtienne Carriere io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 6304b5e93edSEtienne Carriere else 631077d486eSEtienne Carriere io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin)); 6324b5e93edSEtienne Carriere 633c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions); 634*98dfcedaSEtienne Carriere clk_disable(bank->clock); 6354b5e93edSEtienne Carriere } 6360e0435e2SEtienne Carriere 6370e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node, 6380e0435e2SEtienne Carriere const void *compat_data) 6390e0435e2SEtienne Carriere { 6400e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */ 6410e0435e2SEtienne Carriere return dt_stm32_gpio_pinctrl(fdt, node, compat_data); 6420e0435e2SEtienne Carriere } 6430e0435e2SEtienne Carriere 6440e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = { 6450e0435e2SEtienne Carriere { .compatible = "st,stm32mp135-pinctrl" }, 6460e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-pinctrl" }, 6470e0435e2SEtienne Carriere { .compatible = "st,stm32mp157-z-pinctrl" }, 6480e0435e2SEtienne Carriere { } 6490e0435e2SEtienne Carriere }; 6500e0435e2SEtienne Carriere 6510e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = { 6520e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl", 6530e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL, 6540e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table, 6550e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe, 6560e0435e2SEtienne Carriere }; 657