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