xref: /optee_os/core/drivers/stm32_gpio.c (revision 6fdc96626d0894ca3140c44ae6b41498ada65aba)
14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
24b5e93edSEtienne Carriere /*
397391ffbSEtienne Carriere  * Copyright (c) 2017-2021, 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>
224b5e93edSEtienne Carriere #include <trace.h>
234b5e93edSEtienne Carriere #include <util.h>
244b5e93edSEtienne Carriere 
254b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
264b5e93edSEtienne Carriere 
274b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET	0x00
284b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET	0x04
294b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET	0x08
304b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET	0x0c
314b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET		0x10
324b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET		0x14
334b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET	0x18
344b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET	0x20
354b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET	0x24
364b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET	0x30
374b5e93edSEtienne Carriere 
384b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT	0x8
394b5e93edSEtienne Carriere 
404b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
414b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
424b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
43729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
444b5e93edSEtienne Carriere 
454b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT	12
464b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
474b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT	8
484b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
494b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
504b5e93edSEtienne Carriere 
514b5e93edSEtienne Carriere static unsigned int gpio_lock;
524b5e93edSEtienne Carriere 
534b5e93edSEtienne Carriere /* Save to output @cfg the current GPIO (@bank/@pin) configuration */
544b5e93edSEtienne Carriere static void get_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg)
554b5e93edSEtienne Carriere {
564d22155cSEtienne Carriere 	vaddr_t base = stm32_get_gpio_bank_base(bank);
5797391ffbSEtienne Carriere 	struct clk *clk = stm32_get_gpio_bank_clk(bank);
584b5e93edSEtienne Carriere 
5997391ffbSEtienne Carriere 	clk_enable(clk);
604b5e93edSEtienne Carriere 
614b5e93edSEtienne Carriere 	/*
624b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
634b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
644b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
654b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
664b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
674b5e93edSEtienne Carriere 	 */
68918bb3a5SEtienne Carriere 	cfg->mode = (io_read32(base + GPIO_MODER_OFFSET) >> (pin << 1)) &
694b5e93edSEtienne Carriere 		     GPIO_MODE_MASK;
704b5e93edSEtienne Carriere 
71918bb3a5SEtienne Carriere 	cfg->otype = (io_read32(base + GPIO_OTYPER_OFFSET) >> pin) & 1;
724b5e93edSEtienne Carriere 
73918bb3a5SEtienne Carriere 	cfg->ospeed = (io_read32(base +  GPIO_OSPEEDR_OFFSET) >> (pin << 1)) &
744b5e93edSEtienne Carriere 		       GPIO_OSPEED_MASK;
754b5e93edSEtienne Carriere 
76918bb3a5SEtienne Carriere 	cfg->pupd = (io_read32(base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
774b5e93edSEtienne Carriere 		     GPIO_PUPD_PULL_MASK;
784b5e93edSEtienne Carriere 
79918bb3a5SEtienne Carriere 	cfg->od = (io_read32(base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
804b5e93edSEtienne Carriere 
814b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
82918bb3a5SEtienne Carriere 		cfg->af = (io_read32(base + GPIO_AFRL_OFFSET) >> (pin << 2)) &
834b5e93edSEtienne Carriere 			   GPIO_ALTERNATE_MASK;
844b5e93edSEtienne Carriere 	else
85918bb3a5SEtienne Carriere 		cfg->af = (io_read32(base + GPIO_AFRH_OFFSET) >>
864b5e93edSEtienne Carriere 			    ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
874b5e93edSEtienne Carriere 			   GPIO_ALTERNATE_MASK;
884b5e93edSEtienne Carriere 
8997391ffbSEtienne Carriere 	clk_disable(clk);
904b5e93edSEtienne Carriere }
914b5e93edSEtienne Carriere 
924b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
934b5e93edSEtienne Carriere static void set_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg)
944b5e93edSEtienne Carriere {
954d22155cSEtienne Carriere 	vaddr_t base = stm32_get_gpio_bank_base(bank);
9697391ffbSEtienne Carriere 	struct clk *clk = stm32_get_gpio_bank_clk(bank);
97c4cab2bbSEtienne Carriere 	uint32_t exceptions = cpu_spin_lock_xsave(&gpio_lock);
984b5e93edSEtienne Carriere 
9997391ffbSEtienne Carriere 	clk_enable(clk);
1004b5e93edSEtienne Carriere 
1014b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
1024b5e93edSEtienne Carriere 	io_clrsetbits32(base + GPIO_MODER_OFFSET,
1034b5e93edSEtienne Carriere 			GPIO_MODE_MASK << (pin << 1),
1044b5e93edSEtienne Carriere 			cfg->mode << (pin << 1));
1054b5e93edSEtienne Carriere 
1064b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
1074b5e93edSEtienne Carriere 	io_clrsetbits32(base + GPIO_OTYPER_OFFSET, BIT(pin), cfg->otype << pin);
1084b5e93edSEtienne Carriere 
1094b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
1104b5e93edSEtienne Carriere 	io_clrsetbits32(base + GPIO_OSPEEDR_OFFSET,
1114b5e93edSEtienne Carriere 			GPIO_OSPEED_MASK << (pin << 1),
1124b5e93edSEtienne Carriere 			cfg->ospeed << (pin << 1));
1134b5e93edSEtienne Carriere 
1144b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
1154b5e93edSEtienne Carriere 	io_clrsetbits32(base + GPIO_PUPDR_OFFSET, BIT(pin),
1164b5e93edSEtienne Carriere 			cfg->pupd << (pin << 1));
1174b5e93edSEtienne Carriere 
1184b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
1194b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
1204b5e93edSEtienne Carriere 		io_clrsetbits32(base + GPIO_AFRL_OFFSET,
1214b5e93edSEtienne Carriere 				GPIO_ALTERNATE_MASK << (pin << 2),
1224b5e93edSEtienne Carriere 				cfg->af << (pin << 2));
1234b5e93edSEtienne Carriere 	} else {
1244b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
1254b5e93edSEtienne Carriere 
1264b5e93edSEtienne Carriere 		io_clrsetbits32(base + GPIO_AFRH_OFFSET,
1274b5e93edSEtienne Carriere 				GPIO_ALTERNATE_MASK << shift,
1284b5e93edSEtienne Carriere 				cfg->af << shift);
1294b5e93edSEtienne Carriere 	}
1304b5e93edSEtienne Carriere 
1314b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
1324b5e93edSEtienne Carriere 	io_clrsetbits32(base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
1334b5e93edSEtienne Carriere 
13497391ffbSEtienne Carriere 	clk_disable(clk);
135c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
1364b5e93edSEtienne Carriere }
1374b5e93edSEtienne Carriere 
1384b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt)
1394b5e93edSEtienne Carriere {
14010bcbd6cSEtienne Carriere 	size_t n = 0;
1414b5e93edSEtienne Carriere 
1424b5e93edSEtienne Carriere 	for (n = 0; n < cnt; n++)
1434b5e93edSEtienne Carriere 		set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin,
1444b5e93edSEtienne Carriere 			     &pinctrl[n].active_cfg);
1454b5e93edSEtienne Carriere }
1464b5e93edSEtienne Carriere 
1474b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt)
1484b5e93edSEtienne Carriere {
14910bcbd6cSEtienne Carriere 	size_t n = 0;
1504b5e93edSEtienne Carriere 
1514b5e93edSEtienne Carriere 	for (n = 0; n < cnt; n++)
1524b5e93edSEtienne Carriere 		set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin,
1534b5e93edSEtienne Carriere 			     &pinctrl[n].standby_cfg);
1544b5e93edSEtienne Carriere }
1554b5e93edSEtienne Carriere 
1564b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt)
1574b5e93edSEtienne Carriere {
15810bcbd6cSEtienne Carriere 	size_t n = 0;
1594b5e93edSEtienne Carriere 
1604b5e93edSEtienne Carriere 	for (n = 0; n < cnt; n++)
1614b5e93edSEtienne Carriere 		get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin,
1624b5e93edSEtienne Carriere 			     &pinctrl[n].standby_cfg);
1634b5e93edSEtienne Carriere }
1644b5e93edSEtienne Carriere 
1654b5e93edSEtienne Carriere #ifdef CFG_DT
16642f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */
1674b5e93edSEtienne Carriere static void ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node)
1684b5e93edSEtienne Carriere {
16910bcbd6cSEtienne Carriere 	int pinctrl_subnode = 0;
1704b5e93edSEtienne Carriere 
1714b5e93edSEtienne Carriere 	fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
17297391ffbSEtienne Carriere 		TEE_Result res = TEE_ERROR_GENERIC;
17310bcbd6cSEtienne Carriere 		const fdt32_t *cuint = NULL;
17497391ffbSEtienne Carriere 		struct clk *clk = NULL;
1754b5e93edSEtienne Carriere 
1764b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, pinctrl_subnode,
1774b5e93edSEtienne Carriere 				"gpio-controller", NULL) == NULL)
1784b5e93edSEtienne Carriere 			continue;
1794b5e93edSEtienne Carriere 
1804b5e93edSEtienne Carriere 		/* Check bank register offset matches platform assumptions */
1814b5e93edSEtienne Carriere 		cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
1824b5e93edSEtienne Carriere 		if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank))
183563f6249SEtienne Carriere 			continue;
1844b5e93edSEtienne Carriere 
1854b5e93edSEtienne Carriere 		/* Check bank clock matches platform assumptions */
18697391ffbSEtienne Carriere 		res = clk_dt_get_by_index(fdt, pinctrl_subnode, 0, &clk);
18797391ffbSEtienne Carriere 		if (res || clk != stm32_get_gpio_bank_clk(bank))
1884b5e93edSEtienne Carriere 			panic();
1894b5e93edSEtienne Carriere 
1904b5e93edSEtienne Carriere 		/* Check controller is enabled */
1914b5e93edSEtienne Carriere 		if (_fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED)
1924b5e93edSEtienne Carriere 			panic();
1934b5e93edSEtienne Carriere 
1944b5e93edSEtienne Carriere 		return;
1954b5e93edSEtienne Carriere 	}
1964b5e93edSEtienne Carriere 
1974b5e93edSEtienne Carriere 	panic();
1984b5e93edSEtienne Carriere }
1994b5e93edSEtienne Carriere 
2004b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
2014b5e93edSEtienne Carriere static int get_pinctrl_from_fdt(void *fdt, int node,
2024b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
2034b5e93edSEtienne Carriere {
2044b5e93edSEtienne Carriere 	const fdt32_t *cuint, *slewrate;
20510bcbd6cSEtienne Carriere 	int len = 0;
20610bcbd6cSEtienne Carriere 	int pinctrl_node = 0;
20710bcbd6cSEtienne Carriere 	uint32_t i = 0;
2084b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
2094b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
2104b5e93edSEtienne Carriere 	size_t found = 0;
2114b5e93edSEtienne Carriere 
2124b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
2134b5e93edSEtienne Carriere 	if (!cuint)
2144b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
2154b5e93edSEtienne Carriere 
2164b5e93edSEtienne Carriere 	pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
2174b5e93edSEtienne Carriere 	if (pinctrl_node < 0)
2184b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
2194b5e93edSEtienne Carriere 
2204b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
2214b5e93edSEtienne Carriere 	if (slewrate)
2224b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
2234b5e93edSEtienne Carriere 
2244b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
2254b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
2264b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
2274b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
2284b5e93edSEtienne Carriere 
2294b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
23010bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
23110bcbd6cSEtienne Carriere 		uint32_t bank = 0;
23210bcbd6cSEtienne Carriere 		uint32_t pin = 0;
23310bcbd6cSEtienne Carriere 		uint32_t mode = 0;
2344b5e93edSEtienne Carriere 		uint32_t alternate = 0;
2354b5e93edSEtienne Carriere 		bool opendrain = false;
2364b5e93edSEtienne Carriere 
2374b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
2384b5e93edSEtienne Carriere 		cuint++;
2394b5e93edSEtienne Carriere 
2404b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
2414b5e93edSEtienne Carriere 
2424b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
2434b5e93edSEtienne Carriere 
2444b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
2454b5e93edSEtienne Carriere 
2464b5e93edSEtienne Carriere 		switch (mode) {
2474b5e93edSEtienne Carriere 		case 0:
2484b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
2494b5e93edSEtienne Carriere 			break;
2504b5e93edSEtienne Carriere 		case 1:
2514b5e93edSEtienne Carriere 		case 2:
2524b5e93edSEtienne Carriere 		case 3:
2534b5e93edSEtienne Carriere 		case 4:
2544b5e93edSEtienne Carriere 		case 5:
2554b5e93edSEtienne Carriere 		case 6:
2564b5e93edSEtienne Carriere 		case 7:
2574b5e93edSEtienne Carriere 		case 8:
2584b5e93edSEtienne Carriere 		case 9:
2594b5e93edSEtienne Carriere 		case 10:
2604b5e93edSEtienne Carriere 		case 11:
2614b5e93edSEtienne Carriere 		case 12:
2624b5e93edSEtienne Carriere 		case 13:
2634b5e93edSEtienne Carriere 		case 14:
2644b5e93edSEtienne Carriere 		case 15:
2654b5e93edSEtienne Carriere 		case 16:
2664b5e93edSEtienne Carriere 			alternate = mode - 1U;
2674b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
2684b5e93edSEtienne Carriere 			break;
2694b5e93edSEtienne Carriere 		case 17:
2704b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
2714b5e93edSEtienne Carriere 			break;
2724b5e93edSEtienne Carriere 		default:
2734b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
2744b5e93edSEtienne Carriere 			break;
2754b5e93edSEtienne Carriere 		}
2764b5e93edSEtienne Carriere 
2774b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
2784b5e93edSEtienne Carriere 			opendrain = true;
2794b5e93edSEtienne Carriere 
2804b5e93edSEtienne Carriere 		/* Check GPIO bank clock/base address against platform */
2814b5e93edSEtienne Carriere 		ckeck_gpio_bank(fdt, bank, pinctrl_node);
2824b5e93edSEtienne Carriere 
2834b5e93edSEtienne Carriere 		if (found < count) {
2844b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
2854b5e93edSEtienne Carriere 
2864b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
2874b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
2884b5e93edSEtienne Carriere 			ref->active_cfg.mode = mode;
2894b5e93edSEtienne Carriere 			ref->active_cfg.otype = opendrain ? 1 : 0;
2904b5e93edSEtienne Carriere 			ref->active_cfg.ospeed = speed;
2914b5e93edSEtienne Carriere 			ref->active_cfg.pupd = pull;
2924b5e93edSEtienne Carriere 			ref->active_cfg.od = 0;
2934b5e93edSEtienne Carriere 			ref->active_cfg.af = alternate;
2944b5e93edSEtienne Carriere 			/* Default to analog mode for standby state */
2954b5e93edSEtienne Carriere 			ref->standby_cfg.mode = GPIO_MODE_ANALOG;
2964b5e93edSEtienne Carriere 			ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL;
2974b5e93edSEtienne Carriere 		}
2984b5e93edSEtienne Carriere 
2994b5e93edSEtienne Carriere 		found++;
3004b5e93edSEtienne Carriere 	}
3014b5e93edSEtienne Carriere 
3024b5e93edSEtienne Carriere 	return (int)found;
3034b5e93edSEtienne Carriere }
3044b5e93edSEtienne Carriere 
3054b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node,
3064b5e93edSEtienne Carriere 				  struct stm32_pinctrl *pinctrl, size_t count)
3074b5e93edSEtienne Carriere {
30810bcbd6cSEtienne Carriere 	const fdt32_t *cuint = NULL;
30910bcbd6cSEtienne Carriere 	int lenp = 0;
31010bcbd6cSEtienne Carriere 	int i = 0;
3114b5e93edSEtienne Carriere 	size_t found = 0;
3124b5e93edSEtienne Carriere 
3134b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp);
3144b5e93edSEtienne Carriere 	if (!cuint)
3154b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
3164b5e93edSEtienne Carriere 
3174b5e93edSEtienne Carriere 	for (i = 0; i < (lenp / 4); i++) {
31810bcbd6cSEtienne Carriere 		int node = 0;
31910bcbd6cSEtienne Carriere 		int subnode = 0;
3204b5e93edSEtienne Carriere 
3214b5e93edSEtienne Carriere 		node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
3224b5e93edSEtienne Carriere 		if (node < 0)
3234b5e93edSEtienne Carriere 			return -FDT_ERR_NOTFOUND;
3244b5e93edSEtienne Carriere 
3254b5e93edSEtienne Carriere 		fdt_for_each_subnode(subnode, fdt, node) {
32610bcbd6cSEtienne Carriere 			size_t n = 0;
32710bcbd6cSEtienne Carriere 			int rc = 0;
3284b5e93edSEtienne Carriere 
3294b5e93edSEtienne Carriere 			if (count > found)
3304b5e93edSEtienne Carriere 				n = count - found;
3314b5e93edSEtienne Carriere 			else
3324b5e93edSEtienne Carriere 				n = 0;
3334b5e93edSEtienne Carriere 
3344b5e93edSEtienne Carriere 			rc = get_pinctrl_from_fdt(fdt, subnode,
3354b5e93edSEtienne Carriere 						  &pinctrl[found], n);
3364b5e93edSEtienne Carriere 			if (rc < 0)
3374b5e93edSEtienne Carriere 				return rc;
3384b5e93edSEtienne Carriere 
3394b5e93edSEtienne Carriere 			found += (size_t)rc;
3404b5e93edSEtienne Carriere 		}
3414b5e93edSEtienne Carriere 
3424b5e93edSEtienne Carriere 		cuint++;
3434b5e93edSEtienne Carriere 	}
3444b5e93edSEtienne Carriere 
3454b5e93edSEtienne Carriere 	return (int)found;
3464b5e93edSEtienne Carriere }
347a3104caaSEtienne Carriere 
348a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank)
349a3104caaSEtienne Carriere {
350a3104caaSEtienne Carriere 	int node = 0;
351a3104caaSEtienne Carriere 	const fdt32_t *cuint = NULL;
352a3104caaSEtienne Carriere 
353a3104caaSEtienne Carriere 	fdt_for_each_subnode(node, fdt, pinctrl_node) {
354a3104caaSEtienne Carriere 		if (!fdt_getprop(fdt, node, "gpio-controller", NULL))
355a3104caaSEtienne Carriere 			continue;
356a3104caaSEtienne Carriere 
357a3104caaSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "reg", NULL);
358a3104caaSEtienne Carriere 		if (!cuint)
359a3104caaSEtienne Carriere 			continue;
360a3104caaSEtienne Carriere 
361a3104caaSEtienne Carriere 		if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank))
362a3104caaSEtienne Carriere 			continue;
363a3104caaSEtienne Carriere 
364a3104caaSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "ngpios", NULL);
365a3104caaSEtienne Carriere 		if (!cuint)
366a3104caaSEtienne Carriere 			panic();
367a3104caaSEtienne Carriere 
368a3104caaSEtienne Carriere 		return (int)fdt32_to_cpu(*cuint);
369a3104caaSEtienne Carriere 	}
370a3104caaSEtienne Carriere 
371a3104caaSEtienne Carriere 	return -1;
372a3104caaSEtienne Carriere }
3734b5e93edSEtienne Carriere #endif /*CFG_DT*/
3744b5e93edSEtienne Carriere 
3754b5e93edSEtienne Carriere static __maybe_unused bool valid_gpio_config(unsigned int bank,
3764b5e93edSEtienne Carriere 					     unsigned int pin, bool input)
3774b5e93edSEtienne Carriere {
3784d22155cSEtienne Carriere 	vaddr_t base = stm32_get_gpio_bank_base(bank);
379918bb3a5SEtienne Carriere 	uint32_t mode = (io_read32(base + GPIO_MODER_OFFSET) >> (pin << 1)) &
3804b5e93edSEtienne Carriere 			GPIO_MODE_MASK;
3814b5e93edSEtienne Carriere 
3824b5e93edSEtienne Carriere 	if (pin > GPIO_PIN_MAX)
3834b5e93edSEtienne Carriere 		return false;
3844b5e93edSEtienne Carriere 
3854b5e93edSEtienne Carriere 	if (input)
3864b5e93edSEtienne Carriere 		return mode == GPIO_MODE_INPUT;
3874b5e93edSEtienne Carriere 	else
3884b5e93edSEtienne Carriere 		return mode == GPIO_MODE_OUTPUT;
3894b5e93edSEtienne Carriere }
3904b5e93edSEtienne Carriere 
3914b5e93edSEtienne Carriere int stm32_gpio_get_input_level(unsigned int bank, unsigned int pin)
3924b5e93edSEtienne Carriere {
3934d22155cSEtienne Carriere 	vaddr_t base = stm32_get_gpio_bank_base(bank);
39497391ffbSEtienne Carriere 	struct clk *clk = stm32_get_gpio_bank_clk(bank);
3954b5e93edSEtienne Carriere 	int rc = 0;
3964b5e93edSEtienne Carriere 
39797391ffbSEtienne Carriere 	clk_enable(clk);
3984b5e93edSEtienne Carriere 
399*6fdc9662SLoïc Bauer 	assert(valid_gpio_config(bank, pin, true));
400*6fdc9662SLoïc Bauer 
401918bb3a5SEtienne Carriere 	if (io_read32(base + GPIO_IDR_OFFSET) == BIT(pin))
4024b5e93edSEtienne Carriere 		rc = 1;
4034b5e93edSEtienne Carriere 
40497391ffbSEtienne Carriere 	clk_disable(clk);
4054b5e93edSEtienne Carriere 
4064b5e93edSEtienne Carriere 	return rc;
4074b5e93edSEtienne Carriere }
4084b5e93edSEtienne Carriere 
4094b5e93edSEtienne Carriere void stm32_gpio_set_output_level(unsigned int bank, unsigned int pin, int level)
4104b5e93edSEtienne Carriere {
4114d22155cSEtienne Carriere 	vaddr_t base = stm32_get_gpio_bank_base(bank);
41297391ffbSEtienne Carriere 	struct clk *clk = stm32_get_gpio_bank_clk(bank);
4134b5e93edSEtienne Carriere 
41497391ffbSEtienne Carriere 	clk_enable(clk);
4154b5e93edSEtienne Carriere 
416*6fdc9662SLoïc Bauer 	assert(valid_gpio_config(bank, pin, false));
417*6fdc9662SLoïc Bauer 
4184b5e93edSEtienne Carriere 	if (level)
419918bb3a5SEtienne Carriere 		io_write32(base + GPIO_BSRR_OFFSET, BIT(pin));
4204b5e93edSEtienne Carriere 	else
421918bb3a5SEtienne Carriere 		io_write32(base + GPIO_BSRR_OFFSET, BIT(pin + 16));
4224b5e93edSEtienne Carriere 
42397391ffbSEtienne Carriere 	clk_disable(clk);
4244b5e93edSEtienne Carriere }
4254b5e93edSEtienne Carriere 
4264b5e93edSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank, unsigned int pin, bool secure)
4274b5e93edSEtienne Carriere {
4284d22155cSEtienne Carriere 	vaddr_t base = stm32_get_gpio_bank_base(bank);
42997391ffbSEtienne Carriere 	struct clk *clk = stm32_get_gpio_bank_clk(bank);
430c4cab2bbSEtienne Carriere 	uint32_t exceptions = cpu_spin_lock_xsave(&gpio_lock);
4314b5e93edSEtienne Carriere 
43297391ffbSEtienne Carriere 	clk_enable(clk);
4334b5e93edSEtienne Carriere 
4344b5e93edSEtienne Carriere 	if (secure)
4354b5e93edSEtienne Carriere 		io_setbits32(base + GPIO_SECR_OFFSET, BIT(pin));
4364b5e93edSEtienne Carriere 	else
4374b5e93edSEtienne Carriere 		io_clrbits32(base + GPIO_SECR_OFFSET, BIT(pin));
4384b5e93edSEtienne Carriere 
43997391ffbSEtienne Carriere 	clk_disable(clk);
440c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
4414b5e93edSEtienne Carriere }
442