xref: /optee_os/core/drivers/stm32_gpio.c (revision 580e08cf6143ff8542ceb995fdec3225243f1b79)
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>
969715ce9SEtienne Carriere #include <compiler.h>
1097391ffbSEtienne Carriere #include <drivers/clk.h>
1197391ffbSEtienne Carriere #include <drivers/clk_dt.h>
12420a32c5SEtienne Carriere #include <drivers/gpio.h>
13b38386fbSEtienne Carriere #include <drivers/pinctrl.h>
144b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h>
154b5e93edSEtienne Carriere #include <io.h>
164b5e93edSEtienne Carriere #include <kernel/dt.h>
1765401337SJens Wiklander #include <kernel/boot.h>
184b5e93edSEtienne Carriere #include <kernel/panic.h>
194b5e93edSEtienne Carriere #include <kernel/spinlock.h>
20a2fc83d1SJerome Forissier #include <libfdt.h>
214b5e93edSEtienne Carriere #include <mm/core_memprot.h>
224b5e93edSEtienne Carriere #include <stdbool.h>
2369715ce9SEtienne Carriere #include <stdint.h>
244b5e93edSEtienne Carriere #include <stm32_util.h>
259818a481SEtienne Carriere #include <sys/queue.h>
264b5e93edSEtienne Carriere #include <trace.h>
274b5e93edSEtienne Carriere #include <util.h>
284b5e93edSEtienne Carriere 
291001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO
301001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO
311001585eSEtienne Carriere #endif
321001585eSEtienne Carriere 
334b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
344b5e93edSEtienne Carriere 
354b5e93edSEtienne Carriere #define GPIO_MODER_OFFSET	0x00
364b5e93edSEtienne Carriere #define GPIO_OTYPER_OFFSET	0x04
374b5e93edSEtienne Carriere #define GPIO_OSPEEDR_OFFSET	0x08
384b5e93edSEtienne Carriere #define GPIO_PUPDR_OFFSET	0x0c
394b5e93edSEtienne Carriere #define GPIO_IDR_OFFSET		0x10
404b5e93edSEtienne Carriere #define GPIO_ODR_OFFSET		0x14
414b5e93edSEtienne Carriere #define GPIO_BSRR_OFFSET	0x18
424b5e93edSEtienne Carriere #define GPIO_AFRL_OFFSET	0x20
434b5e93edSEtienne Carriere #define GPIO_AFRH_OFFSET	0x24
444b5e93edSEtienne Carriere #define GPIO_SECR_OFFSET	0x30
454b5e93edSEtienne Carriere 
464b5e93edSEtienne Carriere #define GPIO_ALT_LOWER_LIMIT	0x8
474b5e93edSEtienne Carriere 
484b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
494b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
504b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
51729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
524b5e93edSEtienne Carriere 
534b5e93edSEtienne Carriere #define DT_GPIO_BANK_SHIFT	12
544b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
554b5e93edSEtienne Carriere #define DT_GPIO_PIN_SHIFT	8
564b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
574b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
584b5e93edSEtienne Carriere 
599818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0	"GPIOA"
609818a481SEtienne Carriere 
6169715ce9SEtienne Carriere #define GPIO_MODE_INPUT		U(0x0)
6269715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT	U(0x1)
6369715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE	U(0x2)
6469715ce9SEtienne Carriere #define GPIO_MODE_ANALOG	U(0x3)
6569715ce9SEtienne Carriere 
6669715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL	U(0x0)
6769715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN	U(0x1)
6869715ce9SEtienne Carriere 
6969715ce9SEtienne Carriere #define GPIO_OSPEED_LOW		U(0x0)
7069715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM	U(0x1)
7169715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH	U(0x2)
7269715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH	U(0x3)
7369715ce9SEtienne Carriere 
7469715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL	U(0x0)
7569715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP	U(0x1)
7669715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN	U(0x2)
7769715ce9SEtienne Carriere 
7869715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW	U(0x0)
7969715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH	U(0x1)
8069715ce9SEtienne Carriere 
8169715ce9SEtienne Carriere /*
8269715ce9SEtienne Carriere  * GPIO configuration description structured as single 16bit word
8369715ce9SEtienne Carriere  * for efficient save/restore when GPIO pin suspends or resumes.
8469715ce9SEtienne Carriere  *
8569715ce9SEtienne Carriere  * @mode: One of GPIO_MODE_*
8669715ce9SEtienne Carriere  * @otype: One of GPIO_OTYPE_*
8769715ce9SEtienne Carriere  * @ospeed: One of GPIO_OSPEED_*
8869715ce9SEtienne Carriere  * @pupd: One of GPIO_PUPD_*
8969715ce9SEtienne Carriere  * @od: One of GPIO_OD_*
9069715ce9SEtienne Carriere  * @af: Alternate function numerical ID between 0 and 15
9169715ce9SEtienne Carriere  */
9269715ce9SEtienne Carriere struct gpio_cfg {
9369715ce9SEtienne Carriere 	uint16_t mode:		2;
9469715ce9SEtienne Carriere 	uint16_t otype:		1;
9569715ce9SEtienne Carriere 	uint16_t ospeed:	2;
9669715ce9SEtienne Carriere 	uint16_t pupd:		2;
9769715ce9SEtienne Carriere 	uint16_t od:		1;
9869715ce9SEtienne Carriere 	uint16_t af:		4;
9969715ce9SEtienne Carriere };
10069715ce9SEtienne Carriere 
10169715ce9SEtienne Carriere /*
10269715ce9SEtienne Carriere  * Description of a pin and its muxing
10369715ce9SEtienne Carriere  *
10469715ce9SEtienne Carriere  * @bank: GPIO bank identifier as assigned by the platform
10569715ce9SEtienne Carriere  * @pin: Pin number in the GPIO bank
10669715ce9SEtienne Carriere  * @cfg: Pin configuration
10769715ce9SEtienne Carriere  */
10869715ce9SEtienne Carriere struct stm32_pinctrl {
10969715ce9SEtienne Carriere 	uint8_t bank;
11069715ce9SEtienne Carriere 	uint8_t pin;
11169715ce9SEtienne Carriere 	struct gpio_cfg cfg;
11269715ce9SEtienne Carriere };
11369715ce9SEtienne Carriere 
114b38386fbSEtienne Carriere /*
115b38386fbSEtienne Carriere  * struct stm32_pinctrl_array - Array of pins in a pin control state
116b38386fbSEtienne Carriere  * @count: Number of cells in @pinctrl
117b38386fbSEtienne Carriere  * @pinctrl: Pin control configuration
118b38386fbSEtienne Carriere  */
119b38386fbSEtienne Carriere struct stm32_pinctrl_array {
120b38386fbSEtienne Carriere 	size_t count;
121b38386fbSEtienne Carriere 	struct stm32_pinctrl pinctrl[];
122b38386fbSEtienne Carriere };
123b38386fbSEtienne Carriere 
1249818a481SEtienne Carriere /**
1259818a481SEtienne Carriere  * struct stm32_gpio_bank - GPIO bank instance
1269818a481SEtienne Carriere  *
1279818a481SEtienne Carriere  * @base: base address of the GPIO controller registers.
1289818a481SEtienne Carriere  * @clock: clock identifier.
129420a32c5SEtienne Carriere  * @gpio_chip: GPIO chip reference for that GPIO bank
1309818a481SEtienne Carriere  * @ngpios: number of GPIOs.
1319818a481SEtienne Carriere  * @bank_id: Id of the bank.
1329818a481SEtienne Carriere  * @lock: lock protecting the GPIO bank access.
1339818a481SEtienne Carriere  * @sec_support: True if bank supports pin security protection, otherwise false
1349818a481SEtienne Carriere  * @seccfgr: Secure configuration register value.
1359818a481SEtienne Carriere  * @link: Link in bank list
1369818a481SEtienne Carriere  */
1379818a481SEtienne Carriere struct stm32_gpio_bank {
1389818a481SEtienne Carriere 	vaddr_t base;
1399818a481SEtienne Carriere 	struct clk *clock;
140420a32c5SEtienne Carriere 	struct gpio_chip gpio_chip;
1419818a481SEtienne Carriere 	unsigned int ngpios;
1429818a481SEtienne Carriere 	unsigned int bank_id;
1439818a481SEtienne Carriere 	unsigned int lock;
1449818a481SEtienne Carriere 	STAILQ_ENTRY(stm32_gpio_bank) link;
1459818a481SEtienne Carriere };
1469818a481SEtienne Carriere 
147e569f6adSEtienne Carriere /*
148e569f6adSEtienne Carriere  * Compatibility information of supported banks
149e569f6adSEtienne Carriere  * @gpioz True if bank is a GPIOZ bank
150e569f6adSEtienne Carriere  */
151e569f6adSEtienne Carriere struct bank_compat {
152e569f6adSEtienne Carriere 	bool gpioz;
153e569f6adSEtienne Carriere };
154e569f6adSEtienne Carriere 
1554b5e93edSEtienne Carriere static unsigned int gpio_lock;
1564b5e93edSEtienne Carriere 
1579818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
1589818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
1599818a481SEtienne Carriere 
160420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
161420a32c5SEtienne Carriere 
162420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
163420a32c5SEtienne Carriere {
164420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
165420a32c5SEtienne Carriere }
166420a32c5SEtienne Carriere 
167420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
168420a32c5SEtienne Carriere 					    unsigned int gpio_pin)
169420a32c5SEtienne Carriere {
170420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
171420a32c5SEtienne Carriere 	enum gpio_level level = GPIO_LEVEL_HIGH;
172420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
173420a32c5SEtienne Carriere 	unsigned int mode = 0;
174420a32c5SEtienne Carriere 
175420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
1762fd102ebSEtienne Carriere 
1772fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
1782fd102ebSEtienne Carriere 		panic();
179420a32c5SEtienne Carriere 
180420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
181420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
182420a32c5SEtienne Carriere 
183420a32c5SEtienne Carriere 	switch (mode) {
184420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
185420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
186420a32c5SEtienne Carriere 		break;
187420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
188420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
189420a32c5SEtienne Carriere 		break;
190420a32c5SEtienne Carriere 	default:
191420a32c5SEtienne Carriere 		panic();
192420a32c5SEtienne Carriere 	}
193420a32c5SEtienne Carriere 
194420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
195420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
196420a32c5SEtienne Carriere 	else
197420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
198420a32c5SEtienne Carriere 
199420a32c5SEtienne Carriere 	clk_disable(bank->clock);
200420a32c5SEtienne Carriere 
201420a32c5SEtienne Carriere 	return level;
202420a32c5SEtienne Carriere }
203420a32c5SEtienne Carriere 
204420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
205420a32c5SEtienne Carriere 				 enum gpio_level level)
206420a32c5SEtienne Carriere {
207420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
208420a32c5SEtienne Carriere 
209420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2102fd102ebSEtienne Carriere 
2112fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2122fd102ebSEtienne Carriere 		panic();
213420a32c5SEtienne Carriere 
214420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
215420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
216420a32c5SEtienne Carriere 
217420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
218420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
219420a32c5SEtienne Carriere 	else
220420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
221420a32c5SEtienne Carriere 
222420a32c5SEtienne Carriere 	clk_disable(bank->clock);
223420a32c5SEtienne Carriere }
224420a32c5SEtienne Carriere 
225420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
226420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
227420a32c5SEtienne Carriere {
228420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
229420a32c5SEtienne Carriere 	uint32_t mode = 0;
230420a32c5SEtienne Carriere 
231420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2322fd102ebSEtienne Carriere 
2332fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2342fd102ebSEtienne Carriere 		panic();
235420a32c5SEtienne Carriere 
236420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
237420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
238420a32c5SEtienne Carriere 
239420a32c5SEtienne Carriere 	clk_disable(bank->clock);
240420a32c5SEtienne Carriere 
241420a32c5SEtienne Carriere 	switch (mode) {
242420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
243420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
244420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
245420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
246420a32c5SEtienne Carriere 	default:
247420a32c5SEtienne Carriere 		panic();
248420a32c5SEtienne Carriere 	}
249420a32c5SEtienne Carriere }
250420a32c5SEtienne Carriere 
251420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
252420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
253420a32c5SEtienne Carriere 				     enum gpio_dir direction)
254420a32c5SEtienne Carriere {
255420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
256420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
257420a32c5SEtienne Carriere 	uint32_t mode = 0;
258420a32c5SEtienne Carriere 
259420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
260420a32c5SEtienne Carriere 
261420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
262420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
263420a32c5SEtienne Carriere 	else
264420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
265420a32c5SEtienne Carriere 
2662fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2672fd102ebSEtienne Carriere 		panic();
268420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
269420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
270420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
271420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
272420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
273420a32c5SEtienne Carriere 	clk_disable(bank->clock);
274420a32c5SEtienne Carriere }
275420a32c5SEtienne Carriere 
276420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused,
277420a32c5SEtienne Carriere 				struct gpio *gpio)
278420a32c5SEtienne Carriere {
279420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
280420a32c5SEtienne Carriere 	free(gpio);
281420a32c5SEtienne Carriere }
282420a32c5SEtienne Carriere 
283420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
284420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
285420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
286420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
287420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
288420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
289420a32c5SEtienne Carriere };
290420a32c5SEtienne Carriere 
291420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
292420a32c5SEtienne Carriere {
293420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
294420a32c5SEtienne Carriere }
295420a32c5SEtienne Carriere 
296077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
2974b5e93edSEtienne Carriere {
298077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
2994b5e93edSEtienne Carriere 
300077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
301077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
302077d486eSEtienne Carriere 			return bank;
303077d486eSEtienne Carriere 
304077d486eSEtienne Carriere 	panic();
305077d486eSEtienne Carriere }
306077d486eSEtienne Carriere 
307077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
308b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin,
309b38386fbSEtienne Carriere 					struct gpio_cfg *cfg)
310077d486eSEtienne Carriere {
311077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
312077d486eSEtienne Carriere 
313077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
314077d486eSEtienne Carriere 		panic();
3154b5e93edSEtienne Carriere 
3164b5e93edSEtienne Carriere 	/*
3174b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
3184b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
3194b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
3204b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
3214b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
3224b5e93edSEtienne Carriere 	 */
323077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
3244b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
3254b5e93edSEtienne Carriere 
326077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
3274b5e93edSEtienne Carriere 
328077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
329077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
3304b5e93edSEtienne Carriere 
331077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
3324b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
3334b5e93edSEtienne Carriere 
334077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
3354b5e93edSEtienne Carriere 
3364b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
337077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
338077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
3394b5e93edSEtienne Carriere 	else
340077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
3414b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
3424b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
3434b5e93edSEtienne Carriere 
344077d486eSEtienne Carriere 	clk_disable(bank->clock);
3454b5e93edSEtienne Carriere }
3464b5e93edSEtienne Carriere 
3474b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
348077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
3494b5e93edSEtienne Carriere {
350077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
35198dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
3524b5e93edSEtienne Carriere 
353077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
354077d486eSEtienne Carriere 		panic();
35598dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
3564b5e93edSEtienne Carriere 
3574b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
358077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
359bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
360bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
3614b5e93edSEtienne Carriere 
3624b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
363077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
364bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
3654b5e93edSEtienne Carriere 
3664b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
367077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
368bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
369bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
3704b5e93edSEtienne Carriere 
3714b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
372077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
373bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
3744b5e93edSEtienne Carriere 
3754b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
3764b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
377077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
378bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
379bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
3804b5e93edSEtienne Carriere 	} else {
3814b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
3824b5e93edSEtienne Carriere 
383077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
384bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
385bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
3864b5e93edSEtienne Carriere 	}
3874b5e93edSEtienne Carriere 
3884b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
389077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
3904b5e93edSEtienne Carriere 
391c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
39298dfcedaSEtienne Carriere 	clk_disable(bank->clock);
3934b5e93edSEtienne Carriere }
3944b5e93edSEtienne Carriere 
3954b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
396b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
3974b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
3984b5e93edSEtienne Carriere {
399b38386fbSEtienne Carriere 	const fdt32_t *cuint = NULL;
400b38386fbSEtienne Carriere 	const fdt32_t *slewrate = NULL;
40110bcbd6cSEtienne Carriere 	int len = 0;
40210bcbd6cSEtienne Carriere 	uint32_t i = 0;
4034b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
4044b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
4054b5e93edSEtienne Carriere 	size_t found = 0;
4064b5e93edSEtienne Carriere 
4074b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
4084b5e93edSEtienne Carriere 	if (!cuint)
4094b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
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 
4844b5e93edSEtienne Carriere 		if (found < count) {
4854b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
4864b5e93edSEtienne Carriere 
4874b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
4884b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
489b38386fbSEtienne Carriere 			ref->cfg.mode = mode;
490b38386fbSEtienne Carriere 			if (opendrain)
491b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
492b38386fbSEtienne Carriere 			else
493b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
494b38386fbSEtienne Carriere 			ref->cfg.ospeed = speed;
495b38386fbSEtienne Carriere 			ref->cfg.pupd = pull;
496b38386fbSEtienne Carriere 			ref->cfg.od = odata;
497b38386fbSEtienne Carriere 			ref->cfg.af = alternate;
4984b5e93edSEtienne Carriere 		}
4994b5e93edSEtienne Carriere 
5004b5e93edSEtienne Carriere 		found++;
5014b5e93edSEtienne Carriere 	}
5024b5e93edSEtienne Carriere 
5034b5e93edSEtienne Carriere 	return (int)found;
5044b5e93edSEtienne Carriere }
5054b5e93edSEtienne Carriere 
506b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
507b357d34fSEtienne Carriere 				    struct gpio **out_gpio)
508420a32c5SEtienne Carriere {
509b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
510420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
511420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
512420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
513420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
514420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
515420a32c5SEtienne Carriere 	uint32_t otype = 0;
516420a32c5SEtienne Carriere 	uint32_t pupd = 0;
517420a32c5SEtienne Carriere 	uint32_t mode = 0;
518420a32c5SEtienne Carriere 
519b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
520b357d34fSEtienne Carriere 	if (res)
521b357d34fSEtienne Carriere 		return res;
522420a32c5SEtienne Carriere 
523420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
524420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
525420a32c5SEtienne Carriere 		free(gpio);
526b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
527420a32c5SEtienne Carriere 	}
528420a32c5SEtienne Carriere 
529420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
530420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
531420a32c5SEtienne Carriere 
532420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
533420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
534420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
535420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
536420a32c5SEtienne Carriere 	else
537420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
538420a32c5SEtienne Carriere 
539420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
540420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
541420a32c5SEtienne Carriere 	else
542420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
543420a32c5SEtienne Carriere 
544420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
545420a32c5SEtienne Carriere 		panic();
546420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
547420a32c5SEtienne Carriere 
548420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
549420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
550420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
551420a32c5SEtienne Carriere 
552420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
553420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
554420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
555420a32c5SEtienne Carriere 
556420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
557420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
558420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
559420a32c5SEtienne Carriere 
560420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
561420a32c5SEtienne Carriere 	clk_disable(bank->clock);
562420a32c5SEtienne Carriere 
563420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
564420a32c5SEtienne Carriere 
565b357d34fSEtienne Carriere 	*out_gpio = gpio;
566420a32c5SEtienne Carriere 
567b357d34fSEtienne Carriere 	return TEE_SUCCESS;
568420a32c5SEtienne Carriere }
569420a32c5SEtienne Carriere 
5709818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
5719818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
5729818a481SEtienne Carriere {
5739818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
5749818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
5759818a481SEtienne Carriere 	int len = 0;
5769818a481SEtienne Carriere 
5779818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
5789818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
5799818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
5809818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
5819818a481SEtienne Carriere 
5829818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
5839818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
5849818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
5859818a481SEtienne Carriere 
5869818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
5879818a481SEtienne Carriere }
5889818a481SEtienne Carriere 
5899818a481SEtienne Carriere /*
5909818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
5919818a481SEtienne Carriere  * registered in the GPIO bank link.
5929818a481SEtienne Carriere  */
5939818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
5949818a481SEtienne Carriere {
5959818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
5969818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
5979818a481SEtienne Carriere 
5989818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
5999818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
6009818a481SEtienne Carriere 			return true;
6019818a481SEtienne Carriere 
6029818a481SEtienne Carriere 	return false;
6039818a481SEtienne Carriere }
6049818a481SEtienne Carriere 
6059818a481SEtienne Carriere /* Get GPIO bank information from the DT */
6069818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
607e569f6adSEtienne Carriere 				     const void *compat_data,
6089818a481SEtienne Carriere 				     int range_offset,
6099818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
6109818a481SEtienne Carriere {
611e569f6adSEtienne Carriere 	const struct bank_compat *compat = compat_data;
6129818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
6139818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
6149818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6159818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
6169818a481SEtienne Carriere 	struct clk *clk = NULL;
6179818a481SEtienne Carriere 	size_t blen = 0;
6189818a481SEtienne Carriere 	paddr_t pa = 0;
6199818a481SEtienne Carriere 	int len = 0;
6209818a481SEtienne Carriere 	int i = 0;
6219818a481SEtienne Carriere 
6229818a481SEtienne Carriere 	assert(out_bank);
6239818a481SEtienne Carriere 
6249818a481SEtienne Carriere 	/* Probe deferrable devices first */
6259818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
6269818a481SEtienne Carriere 	if (res)
6279818a481SEtienne Carriere 		return res;
6289818a481SEtienne Carriere 
6299818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
6309818a481SEtienne Carriere 	if (!bank)
6319818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
6329818a481SEtienne Carriere 
6339818a481SEtienne Carriere 	/*
6349818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
6359818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
6369818a481SEtienne Carriere 	 */
6379818a481SEtienne Carriere 	pa = fdt_reg_base_address(fdt, node);
6389818a481SEtienne Carriere 	if (pa == DT_INFO_INVALID_REG)
6399818a481SEtienne Carriere 		panic("missing reg property");
6409818a481SEtienne Carriere 
6419818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
6429818a481SEtienne Carriere 
6439818a481SEtienne Carriere 	blen = fdt_reg_size(fdt, node);
6449818a481SEtienne Carriere 	if (blen == DT_INFO_INVALID_REG_SIZE)
6459818a481SEtienne Carriere 		panic("missing reg size property");
6469818a481SEtienne Carriere 
6479818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
6489818a481SEtienne Carriere 	bank->base = io_pa_or_va_secure(&pa_va, blen);
6499818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
6509818a481SEtienne Carriere 	bank->clock = clk;
651420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
6529818a481SEtienne Carriere 
6539818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
6549818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
6559818a481SEtienne Carriere 	len /= sizeof(*cuint);
6569818a481SEtienne Carriere 	if (len % 4)
6579818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
6589818a481SEtienne Carriere 
6599818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
6609818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
6619818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
6629818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
6639818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
6649818a481SEtienne Carriere 		cuint += 4;
6659818a481SEtienne Carriere 	}
6669818a481SEtienne Carriere 
667e569f6adSEtienne Carriere 	if (compat->gpioz)
668e569f6adSEtienne Carriere 		stm32mp_register_gpioz_pin_count(bank->ngpios);
669e569f6adSEtienne Carriere 
6709818a481SEtienne Carriere 	*out_bank = bank;
6719818a481SEtienne Carriere 	return TEE_SUCCESS;
6729818a481SEtienne Carriere }
6739818a481SEtienne Carriere 
674be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank)
675be53ee7bSEtienne Carriere {
676be53ee7bSEtienne Carriere 	unsigned int pin = 0;
677be53ee7bSEtienne Carriere 
678*580e08cfSGatien Chevallier 	for (pin = 0; pin < bank->ngpios; pin++)
679be53ee7bSEtienne Carriere 		stm32_gpio_set_secure_cfg(bank->bank_id, pin, false);
680be53ee7bSEtienne Carriere }
681be53ee7bSEtienne Carriere 
6829818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */
6830e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
6849818a481SEtienne Carriere 					const void *compat_data)
6859818a481SEtienne Carriere {
6869818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
6879818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6889818a481SEtienne Carriere 	int range_offs = 0;
6899818a481SEtienne Carriere 	int b_node = 0;
6909818a481SEtienne Carriere 	int len = 0;
6919818a481SEtienne Carriere 
6929818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
6939818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
6949818a481SEtienne Carriere 	if (!cuint)
6959818a481SEtienne Carriere 		panic("missing ranges property");
6969818a481SEtienne Carriere 
6979818a481SEtienne Carriere 	len /= sizeof(*cuint);
6989818a481SEtienne Carriere 	if (len == 3)
6999818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
7009818a481SEtienne Carriere 
7019818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
7029818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
7039818a481SEtienne Carriere 		if (cuint) {
7049818a481SEtienne Carriere 			/*
7059818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
7069818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
7079818a481SEtienne Carriere 			 * bank list.
7089818a481SEtienne Carriere 			 */
7099818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
7109818a481SEtienne Carriere 
7119818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
7129818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
7139818a481SEtienne Carriere 				continue;
7149818a481SEtienne Carriere 
7159818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
7169818a481SEtienne Carriere 						 range_offs, &bank);
7179818a481SEtienne Carriere 			if (res)
7189818a481SEtienne Carriere 				return res;
7199818a481SEtienne Carriere 
720420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
721420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
722420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
723420a32c5SEtienne Carriere 			if (res)
724420a32c5SEtienne Carriere 				panic();
725420a32c5SEtienne Carriere 
7269818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
727be53ee7bSEtienne Carriere 
728be53ee7bSEtienne Carriere 			if (IS_ENABLED(CFG_STM32MP13))
729be53ee7bSEtienne Carriere 				set_bank_gpio_non_secure(bank);
7309818a481SEtienne Carriere 		} else {
7319818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
7329818a481SEtienne Carriere 				panic();
7339818a481SEtienne Carriere 		}
7349818a481SEtienne Carriere 	}
7359818a481SEtienne Carriere 
7369818a481SEtienne Carriere 	return TEE_SUCCESS;
7379818a481SEtienne Carriere }
7389818a481SEtienne Carriere 
739077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
740077d486eSEtienne Carriere 			       bool secure)
7414b5e93edSEtienne Carriere {
742077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
74398dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
7444b5e93edSEtienne Carriere 
745077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
746077d486eSEtienne Carriere 		panic();
74798dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
7484b5e93edSEtienne Carriere 
7494b5e93edSEtienne Carriere 	if (secure)
750077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
7514b5e93edSEtienne Carriere 	else
752077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
7534b5e93edSEtienne Carriere 
754c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
75598dfcedaSEtienne Carriere 	clk_disable(bank->clock);
7564b5e93edSEtienne Carriere }
7570e0435e2SEtienne Carriere 
758b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
759b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
760b38386fbSEtienne Carriere {
761b38386fbSEtienne Carriere 	struct stm32_pinctrl_array *ref = conf->priv;
762b38386fbSEtienne Carriere 	struct stm32_pinctrl *p = ref->pinctrl;
763b38386fbSEtienne Carriere 	size_t pin_count = ref->count;
764b38386fbSEtienne Carriere 	size_t n = 0;
765b38386fbSEtienne Carriere 
766b38386fbSEtienne Carriere 	for (n = 0; n < pin_count; n++)
767b38386fbSEtienne Carriere 		set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
768b38386fbSEtienne Carriere 
769b38386fbSEtienne Carriere 	return TEE_SUCCESS;
770b38386fbSEtienne Carriere }
771b38386fbSEtienne Carriere 
772b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
773b38386fbSEtienne Carriere {
774b38386fbSEtienne Carriere 	free(conf);
775b38386fbSEtienne Carriere }
776b38386fbSEtienne Carriere 
777b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
778b38386fbSEtienne Carriere 	.conf_apply = stm32_pinctrl_conf_apply,
779b38386fbSEtienne Carriere 	.conf_free = stm32_pinctrl_conf_free,
780b38386fbSEtienne Carriere };
781b38386fbSEtienne Carriere 
782b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
783b38386fbSEtienne Carriere 
78470ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
78570ac0db5SEtienne Carriere 				 unsigned int *bank, unsigned int *pin,
78670ac0db5SEtienne Carriere 				 unsigned int *count)
78770ac0db5SEtienne Carriere {
78870ac0db5SEtienne Carriere 	size_t conf_index = 0;
78970ac0db5SEtienne Carriere 	size_t pin_count = 0;
79070ac0db5SEtienne Carriere 	size_t n = 0;
79170ac0db5SEtienne Carriere 
79270ac0db5SEtienne Carriere 	assert(count);
79370ac0db5SEtienne Carriere 	if (!pinctrl)
79470ac0db5SEtienne Carriere 		goto out;
79570ac0db5SEtienne Carriere 
79670ac0db5SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
79770ac0db5SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
79870ac0db5SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
79970ac0db5SEtienne Carriere 
80070ac0db5SEtienne Carriere 		/* Consider only the stm32_gpio pins */
80170ac0db5SEtienne Carriere 		if (pinconf->ops != &stm32_pinctrl_ops)
80270ac0db5SEtienne Carriere 			continue;
80370ac0db5SEtienne Carriere 
80470ac0db5SEtienne Carriere 		if (bank || pin) {
80570ac0db5SEtienne Carriere 			for (n = 0; n < ref->count; n++) {
80670ac0db5SEtienne Carriere 				if (bank && pin_count < *count)
80770ac0db5SEtienne Carriere 					bank[pin_count] = ref->pinctrl[n].bank;
80870ac0db5SEtienne Carriere 				if (pin && pin_count < *count)
80970ac0db5SEtienne Carriere 					pin[pin_count] = ref->pinctrl[n].pin;
81070ac0db5SEtienne Carriere 				pin_count++;
81170ac0db5SEtienne Carriere 			}
81270ac0db5SEtienne Carriere 		} else {
81370ac0db5SEtienne Carriere 			pin_count += ref->count;
81470ac0db5SEtienne Carriere 		}
81570ac0db5SEtienne Carriere 	}
81670ac0db5SEtienne Carriere 
81770ac0db5SEtienne Carriere out:
81870ac0db5SEtienne Carriere 	*count = pin_count;
81970ac0db5SEtienne Carriere }
82070ac0db5SEtienne Carriere 
8217f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure)
8227f823a77SEtienne Carriere {
8237f823a77SEtienne Carriere 	size_t conf_index = 0;
8247f823a77SEtienne Carriere 
8257f823a77SEtienne Carriere 	if (!pinctrl)
8267f823a77SEtienne Carriere 		return;
8277f823a77SEtienne Carriere 
8287f823a77SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
8297f823a77SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
8307f823a77SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
8317f823a77SEtienne Carriere 		struct stm32_pinctrl *pc = NULL;
8327f823a77SEtienne Carriere 		size_t n = 0;
8337f823a77SEtienne Carriere 
8347f823a77SEtienne Carriere 		for (n = 0; n < ref->count; n++) {
8357f823a77SEtienne Carriere 			if (pinconf->ops != &stm32_pinctrl_ops)
8367f823a77SEtienne Carriere 				continue;
8377f823a77SEtienne Carriere 
8387f823a77SEtienne Carriere 			pc = ref->pinctrl + n;
8397f823a77SEtienne Carriere 			stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure);
8407f823a77SEtienne Carriere 		}
8417f823a77SEtienne Carriere 	}
8427f823a77SEtienne Carriere }
8437f823a77SEtienne Carriere 
844b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
845b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
846b38386fbSEtienne Carriere 				       void *data __unused,
847b38386fbSEtienne Carriere 				       struct pinconf **out_pinconf)
848b38386fbSEtienne Carriere {
849b38386fbSEtienne Carriere 	struct conf {
850b38386fbSEtienne Carriere 		struct pinconf pinconf;
851b38386fbSEtienne Carriere 		struct stm32_pinctrl_array array_ref;
852b38386fbSEtienne Carriere 	} *loc_conf = NULL;
853b38386fbSEtienne Carriere 	struct stm32_pinctrl *pinctrl = NULL;
854b38386fbSEtienne Carriere 	struct pinconf *pinconf = NULL;
855b38386fbSEtienne Carriere 	const void *fdt = NULL;
856b38386fbSEtienne Carriere 	size_t pin_count = 0;
857b38386fbSEtienne Carriere 	int pinctrl_node = 0;
858b38386fbSEtienne Carriere 	int pinmux_node = 0;
859b38386fbSEtienne Carriere 	int count = 0;
860b38386fbSEtienne Carriere 
861b38386fbSEtienne Carriere 	pinctrl_node = pargs->phandle_node;
862b38386fbSEtienne Carriere 	fdt = pargs->fdt;
863b38386fbSEtienne Carriere 	assert(fdt && pinctrl_node);
864b38386fbSEtienne Carriere 
865b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
866b38386fbSEtienne Carriere 		if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
867b38386fbSEtienne Carriere 			pin_count += (size_t)count / sizeof(uint32_t);
868b38386fbSEtienne Carriere 		else if (count != -FDT_ERR_NOTFOUND)
869b38386fbSEtienne Carriere 			panic();
870b38386fbSEtienne Carriere 	}
871b38386fbSEtienne Carriere 
872b38386fbSEtienne Carriere 	loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
873b38386fbSEtienne Carriere 	if (!loc_conf)
874b38386fbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
875b38386fbSEtienne Carriere 
876b38386fbSEtienne Carriere 	pinconf = &loc_conf->pinconf;
877b38386fbSEtienne Carriere 	pinconf->ops = &stm32_pinctrl_ops;
878b38386fbSEtienne Carriere 	pinconf->priv = &loc_conf->array_ref;
879b38386fbSEtienne Carriere 
880b38386fbSEtienne Carriere 	loc_conf->array_ref.count = pin_count;
881b38386fbSEtienne Carriere 	pinctrl = loc_conf->array_ref.pinctrl;
882b38386fbSEtienne Carriere 
883b38386fbSEtienne Carriere 	count = 0;
884b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
885b38386fbSEtienne Carriere 		int found = 0;
886b38386fbSEtienne Carriere 
887b38386fbSEtienne Carriere 		found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count,
888b38386fbSEtienne Carriere 					     pin_count - count);
889b38386fbSEtienne Carriere 		if (found <= 0 && found > ((int)pin_count - count)) {
890b38386fbSEtienne Carriere 			/* We can't recover from an error here so let's panic */
891b38386fbSEtienne Carriere 			panic();
892b38386fbSEtienne Carriere 		}
893b38386fbSEtienne Carriere 
894b38386fbSEtienne Carriere 		count += found;
895b38386fbSEtienne Carriere 	}
896b38386fbSEtienne Carriere 
897b38386fbSEtienne Carriere 	*out_pinconf = pinconf;
898b38386fbSEtienne Carriere 
899b38386fbSEtienne Carriere 	return TEE_SUCCESS;
900b38386fbSEtienne Carriere }
901b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
902b38386fbSEtienne Carriere 
9030e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
9040e0435e2SEtienne Carriere 				      const void *compat_data)
9050e0435e2SEtienne Carriere {
906b38386fbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
907b38386fbSEtienne Carriere 
9080e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
909b38386fbSEtienne Carriere 	res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
910b38386fbSEtienne Carriere 	if (res)
911b38386fbSEtienne Carriere 		return res;
912b38386fbSEtienne Carriere 
913b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
914b38386fbSEtienne Carriere 	res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
915b38386fbSEtienne Carriere 					(void *)compat_data);
916b38386fbSEtienne Carriere 	if (res)
917b38386fbSEtienne Carriere 		return res;
918b38386fbSEtienne Carriere #endif
919b38386fbSEtienne Carriere 
920b38386fbSEtienne Carriere 	return TEE_SUCCESS;
9210e0435e2SEtienne Carriere }
9220e0435e2SEtienne Carriere 
9230e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
924e569f6adSEtienne Carriere 	{
925e569f6adSEtienne Carriere 		.compatible = "st,stm32mp135-pinctrl",
926e569f6adSEtienne Carriere 		.compat_data = &(struct bank_compat){ },
927e569f6adSEtienne Carriere 
928e569f6adSEtienne Carriere 	},
929e569f6adSEtienne Carriere 	{
930e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-pinctrl",
931e569f6adSEtienne Carriere 		.compat_data = &(struct bank_compat){ },
932e569f6adSEtienne Carriere 	},
933e569f6adSEtienne Carriere 	{
934e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-z-pinctrl",
935e569f6adSEtienne Carriere 		.compat_data = &(struct bank_compat){ .gpioz = true, },
936e569f6adSEtienne Carriere 	},
9370e0435e2SEtienne Carriere 	{ }
9380e0435e2SEtienne Carriere };
9390e0435e2SEtienne Carriere 
9400e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
9410e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
9420e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
9430e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
9440e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
9450e0435e2SEtienne Carriere };
946