xref: /optee_os/core/drivers/stm32_gpio.c (revision be53ee7b15f632665b4abfc88b84a96beb0574e1)
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>
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 
261001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO
271001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO
281001585eSEtienne Carriere #endif
291001585eSEtienne Carriere 
304b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
314b5e93edSEtienne Carriere 
324b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET	0x00
334b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET	0x04
344b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET	0x08
354b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET	0x0c
364b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET		0x10
374b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET		0x14
384b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET	0x18
394b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET	0x20
404b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET	0x24
414b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET	0x30
424b5e93edSEtienne Carriere 
434b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT	0x8
444b5e93edSEtienne Carriere 
454b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
464b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
474b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
48729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
494b5e93edSEtienne Carriere 
504b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT	12
514b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
524b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT	8
534b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
544b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
554b5e93edSEtienne Carriere 
569818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0	"GPIOA"
579818a481SEtienne Carriere 
589818a481SEtienne Carriere /**
599818a481SEtienne Carriere  * struct stm32_gpio_bank - GPIO bank instance
609818a481SEtienne Carriere  *
619818a481SEtienne Carriere  * @base: base address of the GPIO controller registers.
629818a481SEtienne Carriere  * @clock: clock identifier.
63420a32c5SEtienne Carriere  * @gpio_chip: GPIO chip reference for that GPIO bank
649818a481SEtienne Carriere  * @ngpios: number of GPIOs.
659818a481SEtienne Carriere  * @bank_id: Id of the bank.
669818a481SEtienne Carriere  * @lock: lock protecting the GPIO bank access.
679818a481SEtienne Carriere  * @sec_support: True if bank supports pin security protection, otherwise false
689818a481SEtienne Carriere  * @seccfgr: Secure configuration register value.
699818a481SEtienne Carriere  * @link: Link in bank list
709818a481SEtienne Carriere  */
719818a481SEtienne Carriere struct stm32_gpio_bank {
729818a481SEtienne Carriere 	vaddr_t base;
739818a481SEtienne Carriere 	struct clk *clock;
74420a32c5SEtienne Carriere 	struct gpio_chip gpio_chip;
759818a481SEtienne Carriere 	unsigned int ngpios;
769818a481SEtienne Carriere 	unsigned int bank_id;
779818a481SEtienne Carriere 	unsigned int lock;
789818a481SEtienne Carriere 	STAILQ_ENTRY(stm32_gpio_bank) link;
799818a481SEtienne Carriere };
809818a481SEtienne Carriere 
814b5e93edSEtienne Carriere static unsigned int gpio_lock;
824b5e93edSEtienne Carriere 
839818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
849818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
859818a481SEtienne Carriere 
86420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
87420a32c5SEtienne Carriere 
88420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
89420a32c5SEtienne Carriere {
90420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
91420a32c5SEtienne Carriere }
92420a32c5SEtienne Carriere 
93420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
94420a32c5SEtienne Carriere 					    unsigned int gpio_pin)
95420a32c5SEtienne Carriere {
96420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
97420a32c5SEtienne Carriere 	enum gpio_level level = GPIO_LEVEL_HIGH;
98420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
99420a32c5SEtienne Carriere 	unsigned int mode = 0;
100420a32c5SEtienne Carriere 
101420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
1022fd102ebSEtienne Carriere 
1032fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
1042fd102ebSEtienne Carriere 		panic();
105420a32c5SEtienne Carriere 
106420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
107420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
108420a32c5SEtienne Carriere 
109420a32c5SEtienne Carriere 	switch (mode) {
110420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
111420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
112420a32c5SEtienne Carriere 		break;
113420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
114420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
115420a32c5SEtienne Carriere 		break;
116420a32c5SEtienne Carriere 	default:
117420a32c5SEtienne Carriere 		panic();
118420a32c5SEtienne Carriere 	}
119420a32c5SEtienne Carriere 
120420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
121420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
122420a32c5SEtienne Carriere 	else
123420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
124420a32c5SEtienne Carriere 
125420a32c5SEtienne Carriere 	clk_disable(bank->clock);
126420a32c5SEtienne Carriere 
127420a32c5SEtienne Carriere 	return level;
128420a32c5SEtienne Carriere }
129420a32c5SEtienne Carriere 
130420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
131420a32c5SEtienne Carriere 				 enum gpio_level level)
132420a32c5SEtienne Carriere {
133420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
134420a32c5SEtienne Carriere 
135420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
1362fd102ebSEtienne Carriere 
1372fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
1382fd102ebSEtienne Carriere 		panic();
139420a32c5SEtienne Carriere 
140420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
141420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
142420a32c5SEtienne Carriere 
143420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
144420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
145420a32c5SEtienne Carriere 	else
146420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
147420a32c5SEtienne Carriere 
148420a32c5SEtienne Carriere 	clk_disable(bank->clock);
149420a32c5SEtienne Carriere }
150420a32c5SEtienne Carriere 
151420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
152420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
153420a32c5SEtienne Carriere {
154420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
155420a32c5SEtienne Carriere 	uint32_t mode = 0;
156420a32c5SEtienne Carriere 
157420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
1582fd102ebSEtienne Carriere 
1592fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
1602fd102ebSEtienne Carriere 		panic();
161420a32c5SEtienne Carriere 
162420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
163420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
164420a32c5SEtienne Carriere 
165420a32c5SEtienne Carriere 	clk_disable(bank->clock);
166420a32c5SEtienne Carriere 
167420a32c5SEtienne Carriere 	switch (mode) {
168420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
169420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
170420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
171420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
172420a32c5SEtienne Carriere 	default:
173420a32c5SEtienne Carriere 		panic();
174420a32c5SEtienne Carriere 	}
175420a32c5SEtienne Carriere }
176420a32c5SEtienne Carriere 
177420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
178420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
179420a32c5SEtienne Carriere 				     enum gpio_dir direction)
180420a32c5SEtienne Carriere {
181420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
182420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
183420a32c5SEtienne Carriere 	uint32_t mode = 0;
184420a32c5SEtienne Carriere 
185420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
186420a32c5SEtienne Carriere 
187420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
188420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
189420a32c5SEtienne Carriere 	else
190420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
191420a32c5SEtienne Carriere 
1922fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
1932fd102ebSEtienne Carriere 		panic();
194420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
195420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
196420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
197420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
198420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
199420a32c5SEtienne Carriere 	clk_disable(bank->clock);
200420a32c5SEtienne Carriere }
201420a32c5SEtienne Carriere 
202420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused,
203420a32c5SEtienne Carriere 				struct gpio *gpio)
204420a32c5SEtienne Carriere {
205420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
206420a32c5SEtienne Carriere 	free(gpio);
207420a32c5SEtienne Carriere }
208420a32c5SEtienne Carriere 
209420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
210420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
211420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
212420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
213420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
214420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
215420a32c5SEtienne Carriere };
216420a32c5SEtienne Carriere 
217420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
218420a32c5SEtienne Carriere {
219420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
220420a32c5SEtienne Carriere }
221420a32c5SEtienne Carriere 
222077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
2234b5e93edSEtienne Carriere {
224077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
2254b5e93edSEtienne Carriere 
226077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
227077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
228077d486eSEtienne Carriere 			return bank;
229077d486eSEtienne Carriere 
230077d486eSEtienne Carriere 	panic();
231077d486eSEtienne Carriere }
232077d486eSEtienne Carriere 
233077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
234077d486eSEtienne Carriere static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
235077d486eSEtienne Carriere {
236077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
237077d486eSEtienne Carriere 
238077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
239077d486eSEtienne Carriere 		panic();
2404b5e93edSEtienne Carriere 
2414b5e93edSEtienne Carriere 	/*
2424b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
2434b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
2444b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
2454b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
2464b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
2474b5e93edSEtienne Carriere 	 */
248077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
2494b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
2504b5e93edSEtienne Carriere 
251077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
2524b5e93edSEtienne Carriere 
253077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
254077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
2554b5e93edSEtienne Carriere 
256077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
2574b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
2584b5e93edSEtienne Carriere 
259077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
2604b5e93edSEtienne Carriere 
2614b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
262077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
263077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
2644b5e93edSEtienne Carriere 	else
265077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
2664b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
2674b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
2684b5e93edSEtienne Carriere 
269077d486eSEtienne Carriere 	clk_disable(bank->clock);
2704b5e93edSEtienne Carriere }
2714b5e93edSEtienne Carriere 
2724b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
273077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
2744b5e93edSEtienne Carriere {
275077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
27698dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
2774b5e93edSEtienne Carriere 
278077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
279077d486eSEtienne Carriere 		panic();
28098dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
2814b5e93edSEtienne Carriere 
2824b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
283077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
284bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
285bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
2864b5e93edSEtienne Carriere 
2874b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
288077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
289bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
2904b5e93edSEtienne Carriere 
2914b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
292077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
293bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
294bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
2954b5e93edSEtienne Carriere 
2964b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
297077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
298bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
2994b5e93edSEtienne Carriere 
3004b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
3014b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
302077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
303bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
304bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
3054b5e93edSEtienne Carriere 	} else {
3064b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
3074b5e93edSEtienne Carriere 
308077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
309bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
310bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
3114b5e93edSEtienne Carriere 	}
3124b5e93edSEtienne Carriere 
3134b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
314077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
3154b5e93edSEtienne Carriere 
316c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
31798dfcedaSEtienne Carriere 	clk_disable(bank->clock);
3184b5e93edSEtienne Carriere }
3194b5e93edSEtienne Carriere 
3204b5e93edSEtienne Carriere void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt)
3214b5e93edSEtienne Carriere {
32210bcbd6cSEtienne Carriere 	size_t n = 0;
3234b5e93edSEtienne Carriere 
3244b5e93edSEtienne Carriere 	for (n = 0; n < cnt; n++)
3254b5e93edSEtienne Carriere 		set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin,
3264b5e93edSEtienne Carriere 			     &pinctrl[n].active_cfg);
3274b5e93edSEtienne Carriere }
3284b5e93edSEtienne Carriere 
3294b5e93edSEtienne Carriere void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt)
3304b5e93edSEtienne Carriere {
33110bcbd6cSEtienne Carriere 	size_t n = 0;
3324b5e93edSEtienne Carriere 
3334b5e93edSEtienne Carriere 	for (n = 0; n < cnt; n++)
3344b5e93edSEtienne Carriere 		set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin,
3354b5e93edSEtienne Carriere 			     &pinctrl[n].standby_cfg);
3364b5e93edSEtienne Carriere }
3374b5e93edSEtienne Carriere 
3384b5e93edSEtienne Carriere void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt)
3394b5e93edSEtienne Carriere {
34010bcbd6cSEtienne Carriere 	size_t n = 0;
3414b5e93edSEtienne Carriere 
3424b5e93edSEtienne Carriere 	for (n = 0; n < cnt; n++)
3434b5e93edSEtienne Carriere 		get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin,
3444b5e93edSEtienne Carriere 			     &pinctrl[n].standby_cfg);
3454b5e93edSEtienne Carriere }
3464b5e93edSEtienne Carriere 
34742f193b6SEtienne Carriere /* Panic if GPIO bank information from platform do not match DTB description */
3484b5e93edSEtienne Carriere static void ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node)
3494b5e93edSEtienne Carriere {
35010bcbd6cSEtienne Carriere 	int pinctrl_subnode = 0;
3514b5e93edSEtienne Carriere 
3524b5e93edSEtienne Carriere 	fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
35310bcbd6cSEtienne Carriere 		const fdt32_t *cuint = NULL;
3544b5e93edSEtienne Carriere 
3554b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, pinctrl_subnode,
3564b5e93edSEtienne Carriere 				"gpio-controller", NULL) == NULL)
3574b5e93edSEtienne Carriere 			continue;
3584b5e93edSEtienne Carriere 
3594b5e93edSEtienne Carriere 		/* Check bank register offset matches platform assumptions */
3604b5e93edSEtienne Carriere 		cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
3614b5e93edSEtienne Carriere 		if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank))
362563f6249SEtienne Carriere 			continue;
3634b5e93edSEtienne Carriere 
3644b5e93edSEtienne Carriere 		/* Check controller is enabled */
365f354a5d8SGatien Chevallier 		if (fdt_get_status(fdt, pinctrl_subnode) == DT_STATUS_DISABLED)
3664b5e93edSEtienne Carriere 			panic();
3674b5e93edSEtienne Carriere 
3684b5e93edSEtienne Carriere 		return;
3694b5e93edSEtienne Carriere 	}
3704b5e93edSEtienne Carriere 
3714b5e93edSEtienne Carriere 	panic();
3724b5e93edSEtienne Carriere }
3734b5e93edSEtienne Carriere 
3744b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
3754b5e93edSEtienne Carriere static int get_pinctrl_from_fdt(void *fdt, int node,
3764b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
3774b5e93edSEtienne Carriere {
3784b5e93edSEtienne Carriere 	const fdt32_t *cuint, *slewrate;
37910bcbd6cSEtienne Carriere 	int len = 0;
38010bcbd6cSEtienne Carriere 	int pinctrl_node = 0;
38110bcbd6cSEtienne Carriere 	uint32_t i = 0;
3824b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
3834b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
3844b5e93edSEtienne Carriere 	size_t found = 0;
3854b5e93edSEtienne Carriere 
3864b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
3874b5e93edSEtienne Carriere 	if (!cuint)
3884b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
3894b5e93edSEtienne Carriere 
3904b5e93edSEtienne Carriere 	pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
3914b5e93edSEtienne Carriere 	if (pinctrl_node < 0)
3924b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
3934b5e93edSEtienne Carriere 
3944b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
3954b5e93edSEtienne Carriere 	if (slewrate)
3964b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
3974b5e93edSEtienne Carriere 
3984b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
3994b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
4004b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
4014b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
4024b5e93edSEtienne Carriere 
4034b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
40410bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
40510bcbd6cSEtienne Carriere 		uint32_t bank = 0;
40610bcbd6cSEtienne Carriere 		uint32_t pin = 0;
40710bcbd6cSEtienne Carriere 		uint32_t mode = 0;
4084b5e93edSEtienne Carriere 		uint32_t alternate = 0;
409322cf9e3SEtienne Carriere 		uint32_t odata = 0;
4104b5e93edSEtienne Carriere 		bool opendrain = false;
4114b5e93edSEtienne Carriere 
4124b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
4134b5e93edSEtienne Carriere 		cuint++;
4144b5e93edSEtienne Carriere 
4154b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
4164b5e93edSEtienne Carriere 
4174b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
4184b5e93edSEtienne Carriere 
4194b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
4204b5e93edSEtienne Carriere 
4214b5e93edSEtienne Carriere 		switch (mode) {
4224b5e93edSEtienne Carriere 		case 0:
4234b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
4244b5e93edSEtienne Carriere 			break;
4254b5e93edSEtienne Carriere 		case 1:
4264b5e93edSEtienne Carriere 		case 2:
4274b5e93edSEtienne Carriere 		case 3:
4284b5e93edSEtienne Carriere 		case 4:
4294b5e93edSEtienne Carriere 		case 5:
4304b5e93edSEtienne Carriere 		case 6:
4314b5e93edSEtienne Carriere 		case 7:
4324b5e93edSEtienne Carriere 		case 8:
4334b5e93edSEtienne Carriere 		case 9:
4344b5e93edSEtienne Carriere 		case 10:
4354b5e93edSEtienne Carriere 		case 11:
4364b5e93edSEtienne Carriere 		case 12:
4374b5e93edSEtienne Carriere 		case 13:
4384b5e93edSEtienne Carriere 		case 14:
4394b5e93edSEtienne Carriere 		case 15:
4404b5e93edSEtienne Carriere 		case 16:
4414b5e93edSEtienne Carriere 			alternate = mode - 1U;
4424b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
4434b5e93edSEtienne Carriere 			break;
4444b5e93edSEtienne Carriere 		case 17:
4454b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
4464b5e93edSEtienne Carriere 			break;
4474b5e93edSEtienne Carriere 		default:
4484b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
4494b5e93edSEtienne Carriere 			break;
4504b5e93edSEtienne Carriere 		}
4514b5e93edSEtienne Carriere 
4524b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
4534b5e93edSEtienne Carriere 			opendrain = true;
4544b5e93edSEtienne Carriere 
455322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-high", NULL) &&
456322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
457322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
458322cf9e3SEtienne Carriere 			odata = 1;
459322cf9e3SEtienne Carriere 		}
460322cf9e3SEtienne Carriere 
461322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-low", NULL) &&
462322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
463322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
464322cf9e3SEtienne Carriere 			odata = 0;
465322cf9e3SEtienne Carriere 		}
466322cf9e3SEtienne Carriere 
4674b5e93edSEtienne Carriere 		/* Check GPIO bank clock/base address against platform */
4684b5e93edSEtienne Carriere 		ckeck_gpio_bank(fdt, bank, pinctrl_node);
4694b5e93edSEtienne Carriere 
4704b5e93edSEtienne Carriere 		if (found < count) {
4714b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
4724b5e93edSEtienne Carriere 
4734b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
4744b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
4754b5e93edSEtienne Carriere 			ref->active_cfg.mode = mode;
4764b5e93edSEtienne Carriere 			ref->active_cfg.otype = opendrain ? 1 : 0;
4774b5e93edSEtienne Carriere 			ref->active_cfg.ospeed = speed;
4784b5e93edSEtienne Carriere 			ref->active_cfg.pupd = pull;
479322cf9e3SEtienne Carriere 			ref->active_cfg.od = odata;
4804b5e93edSEtienne Carriere 			ref->active_cfg.af = alternate;
4814b5e93edSEtienne Carriere 			/* Default to analog mode for standby state */
4824b5e93edSEtienne Carriere 			ref->standby_cfg.mode = GPIO_MODE_ANALOG;
4834b5e93edSEtienne Carriere 			ref->standby_cfg.pupd = GPIO_PUPD_NO_PULL;
4844b5e93edSEtienne Carriere 		}
4854b5e93edSEtienne Carriere 
4864b5e93edSEtienne Carriere 		found++;
4874b5e93edSEtienne Carriere 	}
4884b5e93edSEtienne Carriere 
4894b5e93edSEtienne Carriere 	return (int)found;
4904b5e93edSEtienne Carriere }
4914b5e93edSEtienne Carriere 
492420a32c5SEtienne Carriere static struct gpio *stm32_gpio_get_dt(struct dt_pargs *pargs,
493420a32c5SEtienne Carriere 				      void *data, TEE_Result *res)
494420a32c5SEtienne Carriere {
495420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
496420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
497420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
498420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
499420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
500420a32c5SEtienne Carriere 	uint32_t otype = 0;
501420a32c5SEtienne Carriere 	uint32_t pupd = 0;
502420a32c5SEtienne Carriere 	uint32_t mode = 0;
503420a32c5SEtienne Carriere 
504420a32c5SEtienne Carriere 	gpio = gpio_dt_alloc_pin(pargs, res);
505420a32c5SEtienne Carriere 	if (*res)
506420a32c5SEtienne Carriere 		return NULL;
507420a32c5SEtienne Carriere 
508420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
509420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
510420a32c5SEtienne Carriere 		free(gpio);
511420a32c5SEtienne Carriere 		return NULL;
512420a32c5SEtienne Carriere 	}
513420a32c5SEtienne Carriere 
514420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
515420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
516420a32c5SEtienne Carriere 
517420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
518420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
519420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
520420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
521420a32c5SEtienne Carriere 	else
522420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
523420a32c5SEtienne Carriere 
524420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
525420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
526420a32c5SEtienne Carriere 	else
527420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
528420a32c5SEtienne Carriere 
529420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
530420a32c5SEtienne Carriere 		panic();
531420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
532420a32c5SEtienne Carriere 
533420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
534420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
535420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
536420a32c5SEtienne Carriere 
537420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
538420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
539420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
540420a32c5SEtienne Carriere 
541420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
542420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
543420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
544420a32c5SEtienne Carriere 
545420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
546420a32c5SEtienne Carriere 	clk_disable(bank->clock);
547420a32c5SEtienne Carriere 
548420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
549420a32c5SEtienne Carriere 
550420a32c5SEtienne Carriere 	*res = TEE_SUCCESS;
551420a32c5SEtienne Carriere 
552420a32c5SEtienne Carriere 	return gpio;
553420a32c5SEtienne Carriere }
554420a32c5SEtienne Carriere 
5559818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
5569818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
5579818a481SEtienne Carriere {
5589818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
5599818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
5609818a481SEtienne Carriere 	int len = 0;
5619818a481SEtienne Carriere 
5629818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
5639818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
5649818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
5659818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
5669818a481SEtienne Carriere 
5679818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
5689818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
5699818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
5709818a481SEtienne Carriere 
5719818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
5729818a481SEtienne Carriere }
5739818a481SEtienne Carriere 
5749818a481SEtienne Carriere /*
5759818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
5769818a481SEtienne Carriere  * registered in the GPIO bank link.
5779818a481SEtienne Carriere  */
5789818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
5799818a481SEtienne Carriere {
5809818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
5819818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
5829818a481SEtienne Carriere 
5839818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
5849818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
5859818a481SEtienne Carriere 			return true;
5869818a481SEtienne Carriere 
5879818a481SEtienne Carriere 	return false;
5889818a481SEtienne Carriere }
5899818a481SEtienne Carriere 
5909818a481SEtienne Carriere /* Get GPIO bank information from the DT */
5919818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
5929818a481SEtienne Carriere 				     const void *compat_data __unused,
5939818a481SEtienne Carriere 				     int range_offset,
5949818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
5959818a481SEtienne Carriere {
5969818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
5979818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
5989818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
5999818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
6009818a481SEtienne Carriere 	struct clk *clk = NULL;
6019818a481SEtienne Carriere 	size_t blen = 0;
6029818a481SEtienne Carriere 	paddr_t pa = 0;
6039818a481SEtienne Carriere 	int len = 0;
6049818a481SEtienne Carriere 	int i = 0;
6059818a481SEtienne Carriere 
6069818a481SEtienne Carriere 	assert(out_bank);
6079818a481SEtienne Carriere 
6089818a481SEtienne Carriere 	/* Probe deferrable devices first */
6099818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
6109818a481SEtienne Carriere 	if (res)
6119818a481SEtienne Carriere 		return res;
6129818a481SEtienne Carriere 
6139818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
6149818a481SEtienne Carriere 	if (!bank)
6159818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
6169818a481SEtienne Carriere 
6179818a481SEtienne Carriere 	/*
6189818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
6199818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
6209818a481SEtienne Carriere 	 */
6219818a481SEtienne Carriere 	pa = fdt_reg_base_address(fdt, node);
6229818a481SEtienne Carriere 	if (pa == DT_INFO_INVALID_REG)
6239818a481SEtienne Carriere 		panic("missing reg property");
6249818a481SEtienne Carriere 
6259818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
6269818a481SEtienne Carriere 
6279818a481SEtienne Carriere 	blen = fdt_reg_size(fdt, node);
6289818a481SEtienne Carriere 	if (blen == DT_INFO_INVALID_REG_SIZE)
6299818a481SEtienne Carriere 		panic("missing reg size property");
6309818a481SEtienne Carriere 
6319818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
6329818a481SEtienne Carriere 	bank->base = io_pa_or_va_secure(&pa_va, blen);
6339818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
6349818a481SEtienne Carriere 	bank->clock = clk;
635420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
6369818a481SEtienne Carriere 
6379818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
6389818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
6399818a481SEtienne Carriere 	len /= sizeof(*cuint);
6409818a481SEtienne Carriere 	if (len % 4)
6419818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
6429818a481SEtienne Carriere 
6439818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
6449818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
6459818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
6469818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
6479818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
6489818a481SEtienne Carriere 		cuint += 4;
6499818a481SEtienne Carriere 	}
6509818a481SEtienne Carriere 
6519818a481SEtienne Carriere 	*out_bank = bank;
6529818a481SEtienne Carriere 	return TEE_SUCCESS;
6539818a481SEtienne Carriere }
6549818a481SEtienne Carriere 
655*be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank)
656*be53ee7bSEtienne Carriere {
657*be53ee7bSEtienne Carriere 	unsigned int pin = 0;
658*be53ee7bSEtienne Carriere 
659*be53ee7bSEtienne Carriere 	for (pin = 0; pin <= bank->ngpios; pin++)
660*be53ee7bSEtienne Carriere 		stm32_gpio_set_secure_cfg(bank->bank_id, pin, false);
661*be53ee7bSEtienne Carriere }
662*be53ee7bSEtienne Carriere 
6639818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */
6640e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
6659818a481SEtienne Carriere 					const void *compat_data)
6669818a481SEtienne Carriere {
6679818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
6689818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6699818a481SEtienne Carriere 	int range_offs = 0;
6709818a481SEtienne Carriere 	int b_node = 0;
6719818a481SEtienne Carriere 	int len = 0;
6729818a481SEtienne Carriere 
6739818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
6749818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
6759818a481SEtienne Carriere 	if (!cuint)
6769818a481SEtienne Carriere 		panic("missing ranges property");
6779818a481SEtienne Carriere 
6789818a481SEtienne Carriere 	len /= sizeof(*cuint);
6799818a481SEtienne Carriere 	if (len == 3)
6809818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
6819818a481SEtienne Carriere 
6829818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
6839818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
6849818a481SEtienne Carriere 		if (cuint) {
6859818a481SEtienne Carriere 			/*
6869818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
6879818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
6889818a481SEtienne Carriere 			 * bank list.
6899818a481SEtienne Carriere 			 */
6909818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
6919818a481SEtienne Carriere 
6929818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
6939818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
6949818a481SEtienne Carriere 				continue;
6959818a481SEtienne Carriere 
6969818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
6979818a481SEtienne Carriere 						 range_offs, &bank);
6989818a481SEtienne Carriere 			if (res)
6999818a481SEtienne Carriere 				return res;
7009818a481SEtienne Carriere 
701420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
702420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
703420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
704420a32c5SEtienne Carriere 			if (res)
705420a32c5SEtienne Carriere 				panic();
706420a32c5SEtienne Carriere 
7079818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
708*be53ee7bSEtienne Carriere 
709*be53ee7bSEtienne Carriere 			if (IS_ENABLED(CFG_STM32MP13))
710*be53ee7bSEtienne Carriere 				set_bank_gpio_non_secure(bank);
7119818a481SEtienne Carriere 		} else {
7129818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
7139818a481SEtienne Carriere 				panic();
7149818a481SEtienne Carriere 		}
7159818a481SEtienne Carriere 	}
7169818a481SEtienne Carriere 
7179818a481SEtienne Carriere 	return TEE_SUCCESS;
7189818a481SEtienne Carriere }
7199818a481SEtienne Carriere 
7204b5e93edSEtienne Carriere int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node,
7214b5e93edSEtienne Carriere 				  struct stm32_pinctrl *pinctrl, size_t count)
7224b5e93edSEtienne Carriere {
72310bcbd6cSEtienne Carriere 	const fdt32_t *cuint = NULL;
72410bcbd6cSEtienne Carriere 	int lenp = 0;
72510bcbd6cSEtienne Carriere 	int i = 0;
7264b5e93edSEtienne Carriere 	size_t found = 0;
7274b5e93edSEtienne Carriere 
7284b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp);
7294b5e93edSEtienne Carriere 	if (!cuint)
7304b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
7314b5e93edSEtienne Carriere 
7324b5e93edSEtienne Carriere 	for (i = 0; i < (lenp / 4); i++) {
73310bcbd6cSEtienne Carriere 		int node = 0;
73410bcbd6cSEtienne Carriere 		int subnode = 0;
7354b5e93edSEtienne Carriere 
7364b5e93edSEtienne Carriere 		node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
7374b5e93edSEtienne Carriere 		if (node < 0)
7384b5e93edSEtienne Carriere 			return -FDT_ERR_NOTFOUND;
7394b5e93edSEtienne Carriere 
7404b5e93edSEtienne Carriere 		fdt_for_each_subnode(subnode, fdt, node) {
74110bcbd6cSEtienne Carriere 			size_t n = 0;
74210bcbd6cSEtienne Carriere 			int rc = 0;
7434b5e93edSEtienne Carriere 
7444b5e93edSEtienne Carriere 			if (count > found)
7454b5e93edSEtienne Carriere 				n = count - found;
7464b5e93edSEtienne Carriere 			else
7474b5e93edSEtienne Carriere 				n = 0;
7484b5e93edSEtienne Carriere 
7494b5e93edSEtienne Carriere 			rc = get_pinctrl_from_fdt(fdt, subnode,
7504b5e93edSEtienne Carriere 						  &pinctrl[found], n);
7514b5e93edSEtienne Carriere 			if (rc < 0)
7524b5e93edSEtienne Carriere 				return rc;
7534b5e93edSEtienne Carriere 
7544b5e93edSEtienne Carriere 			found += (size_t)rc;
7554b5e93edSEtienne Carriere 		}
7564b5e93edSEtienne Carriere 
7574b5e93edSEtienne Carriere 		cuint++;
7584b5e93edSEtienne Carriere 	}
7594b5e93edSEtienne Carriere 
7604b5e93edSEtienne Carriere 	return (int)found;
7614b5e93edSEtienne Carriere }
762a3104caaSEtienne Carriere 
763a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank)
764a3104caaSEtienne Carriere {
765a3104caaSEtienne Carriere 	int node = 0;
766a3104caaSEtienne Carriere 	const fdt32_t *cuint = NULL;
767a3104caaSEtienne Carriere 
768a3104caaSEtienne Carriere 	fdt_for_each_subnode(node, fdt, pinctrl_node) {
769a3104caaSEtienne Carriere 		if (!fdt_getprop(fdt, node, "gpio-controller", NULL))
770a3104caaSEtienne Carriere 			continue;
771a3104caaSEtienne Carriere 
772a3104caaSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "reg", NULL);
773a3104caaSEtienne Carriere 		if (!cuint)
774a3104caaSEtienne Carriere 			continue;
775a3104caaSEtienne Carriere 
776a3104caaSEtienne Carriere 		if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank))
777a3104caaSEtienne Carriere 			continue;
778a3104caaSEtienne Carriere 
779a3104caaSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "ngpios", NULL);
780a3104caaSEtienne Carriere 		if (!cuint)
781a3104caaSEtienne Carriere 			panic();
782a3104caaSEtienne Carriere 
783a3104caaSEtienne Carriere 		return (int)fdt32_to_cpu(*cuint);
784a3104caaSEtienne Carriere 	}
785a3104caaSEtienne Carriere 
786a3104caaSEtienne Carriere 	return -1;
787a3104caaSEtienne Carriere }
7884b5e93edSEtienne Carriere 
789077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
790077d486eSEtienne Carriere 			       bool secure)
7914b5e93edSEtienne Carriere {
792077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
79398dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
7944b5e93edSEtienne Carriere 
795077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
796077d486eSEtienne Carriere 		panic();
79798dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
7984b5e93edSEtienne Carriere 
7994b5e93edSEtienne Carriere 	if (secure)
800077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
8014b5e93edSEtienne Carriere 	else
802077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
8034b5e93edSEtienne Carriere 
804c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
80598dfcedaSEtienne Carriere 	clk_disable(bank->clock);
8064b5e93edSEtienne Carriere }
8070e0435e2SEtienne Carriere 
8080e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
8090e0435e2SEtienne Carriere 				      const void *compat_data)
8100e0435e2SEtienne Carriere {
8110e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
8120e0435e2SEtienne Carriere 	return dt_stm32_gpio_pinctrl(fdt, node, compat_data);
8130e0435e2SEtienne Carriere }
8140e0435e2SEtienne Carriere 
8150e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
8160e0435e2SEtienne Carriere 	{ .compatible = "st,stm32mp135-pinctrl" },
8170e0435e2SEtienne Carriere 	{ .compatible = "st,stm32mp157-pinctrl" },
8180e0435e2SEtienne Carriere 	{ .compatible = "st,stm32mp157-z-pinctrl" },
8190e0435e2SEtienne Carriere 	{ }
8200e0435e2SEtienne Carriere };
8210e0435e2SEtienne Carriere 
8220e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
8230e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
8240e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
8250e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
8260e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
8270e0435e2SEtienne Carriere };
828