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