xref: /optee_os/core/drivers/stm32_gpio.c (revision 69715ce97ef2ac050e62b882e33a1c2700000e96)
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>
9*69715ce9SEtienne 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>
23*69715ce9SEtienne 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 
61*69715ce9SEtienne Carriere #define GPIO_MODE_INPUT		U(0x0)
62*69715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT	U(0x1)
63*69715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE	U(0x2)
64*69715ce9SEtienne Carriere #define GPIO_MODE_ANALOG	U(0x3)
65*69715ce9SEtienne Carriere 
66*69715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL	U(0x0)
67*69715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN	U(0x1)
68*69715ce9SEtienne Carriere 
69*69715ce9SEtienne Carriere #define GPIO_OSPEED_LOW		U(0x0)
70*69715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM	U(0x1)
71*69715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH	U(0x2)
72*69715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH	U(0x3)
73*69715ce9SEtienne Carriere 
74*69715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL	U(0x0)
75*69715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP	U(0x1)
76*69715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN	U(0x2)
77*69715ce9SEtienne Carriere 
78*69715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW	U(0x0)
79*69715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH	U(0x1)
80*69715ce9SEtienne Carriere 
81*69715ce9SEtienne Carriere /*
82*69715ce9SEtienne Carriere  * GPIO configuration description structured as single 16bit word
83*69715ce9SEtienne Carriere  * for efficient save/restore when GPIO pin suspends or resumes.
84*69715ce9SEtienne Carriere  *
85*69715ce9SEtienne Carriere  * @mode: One of GPIO_MODE_*
86*69715ce9SEtienne Carriere  * @otype: One of GPIO_OTYPE_*
87*69715ce9SEtienne Carriere  * @ospeed: One of GPIO_OSPEED_*
88*69715ce9SEtienne Carriere  * @pupd: One of GPIO_PUPD_*
89*69715ce9SEtienne Carriere  * @od: One of GPIO_OD_*
90*69715ce9SEtienne Carriere  * @af: Alternate function numerical ID between 0 and 15
91*69715ce9SEtienne Carriere  */
92*69715ce9SEtienne Carriere struct gpio_cfg {
93*69715ce9SEtienne Carriere 	uint16_t mode:		2;
94*69715ce9SEtienne Carriere 	uint16_t otype:		1;
95*69715ce9SEtienne Carriere 	uint16_t ospeed:	2;
96*69715ce9SEtienne Carriere 	uint16_t pupd:		2;
97*69715ce9SEtienne Carriere 	uint16_t od:		1;
98*69715ce9SEtienne Carriere 	uint16_t af:		4;
99*69715ce9SEtienne Carriere };
100*69715ce9SEtienne Carriere 
101*69715ce9SEtienne Carriere /*
102*69715ce9SEtienne Carriere  * Description of a pin and its muxing
103*69715ce9SEtienne Carriere  *
104*69715ce9SEtienne Carriere  * @bank: GPIO bank identifier as assigned by the platform
105*69715ce9SEtienne Carriere  * @pin: Pin number in the GPIO bank
106*69715ce9SEtienne Carriere  * @cfg: Pin configuration
107*69715ce9SEtienne Carriere  */
108*69715ce9SEtienne Carriere struct stm32_pinctrl {
109*69715ce9SEtienne Carriere 	uint8_t bank;
110*69715ce9SEtienne Carriere 	uint8_t pin;
111*69715ce9SEtienne Carriere 	struct gpio_cfg cfg;
112*69715ce9SEtienne Carriere };
113*69715ce9SEtienne 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 
1474b5e93edSEtienne Carriere static unsigned int gpio_lock;
1484b5e93edSEtienne Carriere 
1499818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
1509818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
1519818a481SEtienne Carriere 
152420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
153420a32c5SEtienne Carriere 
154420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
155420a32c5SEtienne Carriere {
156420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
157420a32c5SEtienne Carriere }
158420a32c5SEtienne Carriere 
159420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
160420a32c5SEtienne Carriere 					    unsigned int gpio_pin)
161420a32c5SEtienne Carriere {
162420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
163420a32c5SEtienne Carriere 	enum gpio_level level = GPIO_LEVEL_HIGH;
164420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
165420a32c5SEtienne Carriere 	unsigned int mode = 0;
166420a32c5SEtienne Carriere 
167420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
1682fd102ebSEtienne Carriere 
1692fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
1702fd102ebSEtienne Carriere 		panic();
171420a32c5SEtienne Carriere 
172420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
173420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
174420a32c5SEtienne Carriere 
175420a32c5SEtienne Carriere 	switch (mode) {
176420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
177420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
178420a32c5SEtienne Carriere 		break;
179420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
180420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
181420a32c5SEtienne Carriere 		break;
182420a32c5SEtienne Carriere 	default:
183420a32c5SEtienne Carriere 		panic();
184420a32c5SEtienne Carriere 	}
185420a32c5SEtienne Carriere 
186420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
187420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
188420a32c5SEtienne Carriere 	else
189420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
190420a32c5SEtienne Carriere 
191420a32c5SEtienne Carriere 	clk_disable(bank->clock);
192420a32c5SEtienne Carriere 
193420a32c5SEtienne Carriere 	return level;
194420a32c5SEtienne Carriere }
195420a32c5SEtienne Carriere 
196420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
197420a32c5SEtienne Carriere 				 enum gpio_level level)
198420a32c5SEtienne Carriere {
199420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
200420a32c5SEtienne Carriere 
201420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2022fd102ebSEtienne Carriere 
2032fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2042fd102ebSEtienne Carriere 		panic();
205420a32c5SEtienne Carriere 
206420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
207420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
208420a32c5SEtienne Carriere 
209420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
210420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
211420a32c5SEtienne Carriere 	else
212420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
213420a32c5SEtienne Carriere 
214420a32c5SEtienne Carriere 	clk_disable(bank->clock);
215420a32c5SEtienne Carriere }
216420a32c5SEtienne Carriere 
217420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
218420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
219420a32c5SEtienne Carriere {
220420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
221420a32c5SEtienne Carriere 	uint32_t mode = 0;
222420a32c5SEtienne Carriere 
223420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2242fd102ebSEtienne Carriere 
2252fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2262fd102ebSEtienne Carriere 		panic();
227420a32c5SEtienne Carriere 
228420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
229420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
230420a32c5SEtienne Carriere 
231420a32c5SEtienne Carriere 	clk_disable(bank->clock);
232420a32c5SEtienne Carriere 
233420a32c5SEtienne Carriere 	switch (mode) {
234420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
235420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
236420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
237420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
238420a32c5SEtienne Carriere 	default:
239420a32c5SEtienne Carriere 		panic();
240420a32c5SEtienne Carriere 	}
241420a32c5SEtienne Carriere }
242420a32c5SEtienne Carriere 
243420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
244420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
245420a32c5SEtienne Carriere 				     enum gpio_dir direction)
246420a32c5SEtienne Carriere {
247420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
248420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
249420a32c5SEtienne Carriere 	uint32_t mode = 0;
250420a32c5SEtienne Carriere 
251420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
252420a32c5SEtienne Carriere 
253420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
254420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
255420a32c5SEtienne Carriere 	else
256420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
257420a32c5SEtienne Carriere 
2582fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2592fd102ebSEtienne Carriere 		panic();
260420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
261420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
262420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
263420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
264420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
265420a32c5SEtienne Carriere 	clk_disable(bank->clock);
266420a32c5SEtienne Carriere }
267420a32c5SEtienne Carriere 
268420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused,
269420a32c5SEtienne Carriere 				struct gpio *gpio)
270420a32c5SEtienne Carriere {
271420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
272420a32c5SEtienne Carriere 	free(gpio);
273420a32c5SEtienne Carriere }
274420a32c5SEtienne Carriere 
275420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
276420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
277420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
278420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
279420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
280420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
281420a32c5SEtienne Carriere };
282420a32c5SEtienne Carriere 
283420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
284420a32c5SEtienne Carriere {
285420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
286420a32c5SEtienne Carriere }
287420a32c5SEtienne Carriere 
288077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
2894b5e93edSEtienne Carriere {
290077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
2914b5e93edSEtienne Carriere 
292077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
293077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
294077d486eSEtienne Carriere 			return bank;
295077d486eSEtienne Carriere 
296077d486eSEtienne Carriere 	panic();
297077d486eSEtienne Carriere }
298077d486eSEtienne Carriere 
299077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
300b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin,
301b38386fbSEtienne Carriere 					struct gpio_cfg *cfg)
302077d486eSEtienne Carriere {
303077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
304077d486eSEtienne Carriere 
305077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
306077d486eSEtienne Carriere 		panic();
3074b5e93edSEtienne Carriere 
3084b5e93edSEtienne Carriere 	/*
3094b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
3104b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
3114b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
3124b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
3134b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
3144b5e93edSEtienne Carriere 	 */
315077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
3164b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
3174b5e93edSEtienne Carriere 
318077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
3194b5e93edSEtienne Carriere 
320077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
321077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
3224b5e93edSEtienne Carriere 
323077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
3244b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
3254b5e93edSEtienne Carriere 
326077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
3274b5e93edSEtienne Carriere 
3284b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
329077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
330077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
3314b5e93edSEtienne Carriere 	else
332077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
3334b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
3344b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
3354b5e93edSEtienne Carriere 
336077d486eSEtienne Carriere 	clk_disable(bank->clock);
3374b5e93edSEtienne Carriere }
3384b5e93edSEtienne Carriere 
3394b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
340077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
3414b5e93edSEtienne Carriere {
342077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
34398dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
3444b5e93edSEtienne Carriere 
345077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
346077d486eSEtienne Carriere 		panic();
34798dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
3484b5e93edSEtienne Carriere 
3494b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
350077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
351bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
352bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
3534b5e93edSEtienne Carriere 
3544b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
355077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
356bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
3574b5e93edSEtienne Carriere 
3584b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
359077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
360bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
361bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
3624b5e93edSEtienne Carriere 
3634b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
364077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
365bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
3664b5e93edSEtienne Carriere 
3674b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
3684b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
369077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
370bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
371bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
3724b5e93edSEtienne Carriere 	} else {
3734b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
3744b5e93edSEtienne Carriere 
375077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
376bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
377bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
3784b5e93edSEtienne Carriere 	}
3794b5e93edSEtienne Carriere 
3804b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
381077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
3824b5e93edSEtienne Carriere 
383c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
38498dfcedaSEtienne Carriere 	clk_disable(bank->clock);
3854b5e93edSEtienne Carriere }
3864b5e93edSEtienne Carriere 
3874b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
388b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
3894b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
3904b5e93edSEtienne Carriere {
391b38386fbSEtienne Carriere 	const fdt32_t *cuint = NULL;
392b38386fbSEtienne Carriere 	const fdt32_t *slewrate = NULL;
39310bcbd6cSEtienne Carriere 	int len = 0;
39410bcbd6cSEtienne Carriere 	uint32_t i = 0;
3954b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
3964b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
3974b5e93edSEtienne Carriere 	size_t found = 0;
3984b5e93edSEtienne Carriere 
3994b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
4004b5e93edSEtienne Carriere 	if (!cuint)
4014b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
4024b5e93edSEtienne Carriere 
4034b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
4044b5e93edSEtienne Carriere 	if (slewrate)
4054b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
4064b5e93edSEtienne Carriere 
4074b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
4084b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
4094b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
4104b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
4114b5e93edSEtienne Carriere 
4124b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
41310bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
41410bcbd6cSEtienne Carriere 		uint32_t bank = 0;
41510bcbd6cSEtienne Carriere 		uint32_t pin = 0;
41610bcbd6cSEtienne Carriere 		uint32_t mode = 0;
4174b5e93edSEtienne Carriere 		uint32_t alternate = 0;
418322cf9e3SEtienne Carriere 		uint32_t odata = 0;
4194b5e93edSEtienne Carriere 		bool opendrain = false;
4204b5e93edSEtienne Carriere 
4214b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
4224b5e93edSEtienne Carriere 		cuint++;
4234b5e93edSEtienne Carriere 
4244b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
4254b5e93edSEtienne Carriere 
4264b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
4274b5e93edSEtienne Carriere 
4284b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
4294b5e93edSEtienne Carriere 
4304b5e93edSEtienne Carriere 		switch (mode) {
4314b5e93edSEtienne Carriere 		case 0:
4324b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
4334b5e93edSEtienne Carriere 			break;
4344b5e93edSEtienne Carriere 		case 1:
4354b5e93edSEtienne Carriere 		case 2:
4364b5e93edSEtienne Carriere 		case 3:
4374b5e93edSEtienne Carriere 		case 4:
4384b5e93edSEtienne Carriere 		case 5:
4394b5e93edSEtienne Carriere 		case 6:
4404b5e93edSEtienne Carriere 		case 7:
4414b5e93edSEtienne Carriere 		case 8:
4424b5e93edSEtienne Carriere 		case 9:
4434b5e93edSEtienne Carriere 		case 10:
4444b5e93edSEtienne Carriere 		case 11:
4454b5e93edSEtienne Carriere 		case 12:
4464b5e93edSEtienne Carriere 		case 13:
4474b5e93edSEtienne Carriere 		case 14:
4484b5e93edSEtienne Carriere 		case 15:
4494b5e93edSEtienne Carriere 		case 16:
4504b5e93edSEtienne Carriere 			alternate = mode - 1U;
4514b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
4524b5e93edSEtienne Carriere 			break;
4534b5e93edSEtienne Carriere 		case 17:
4544b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
4554b5e93edSEtienne Carriere 			break;
4564b5e93edSEtienne Carriere 		default:
4574b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
4584b5e93edSEtienne Carriere 			break;
4594b5e93edSEtienne Carriere 		}
4604b5e93edSEtienne Carriere 
4614b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
4624b5e93edSEtienne Carriere 			opendrain = true;
4634b5e93edSEtienne Carriere 
464322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-high", NULL) &&
465322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
466322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
467322cf9e3SEtienne Carriere 			odata = 1;
468322cf9e3SEtienne Carriere 		}
469322cf9e3SEtienne Carriere 
470322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-low", NULL) &&
471322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
472322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
473322cf9e3SEtienne Carriere 			odata = 0;
474322cf9e3SEtienne Carriere 		}
475322cf9e3SEtienne Carriere 
4764b5e93edSEtienne Carriere 		if (found < count) {
4774b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
4784b5e93edSEtienne Carriere 
4794b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
4804b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
481b38386fbSEtienne Carriere 			ref->cfg.mode = mode;
482b38386fbSEtienne Carriere 			if (opendrain)
483b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
484b38386fbSEtienne Carriere 			else
485b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
486b38386fbSEtienne Carriere 			ref->cfg.ospeed = speed;
487b38386fbSEtienne Carriere 			ref->cfg.pupd = pull;
488b38386fbSEtienne Carriere 			ref->cfg.od = odata;
489b38386fbSEtienne Carriere 			ref->cfg.af = alternate;
4904b5e93edSEtienne Carriere 		}
4914b5e93edSEtienne Carriere 
4924b5e93edSEtienne Carriere 		found++;
4934b5e93edSEtienne Carriere 	}
4944b5e93edSEtienne Carriere 
4954b5e93edSEtienne Carriere 	return (int)found;
4964b5e93edSEtienne Carriere }
4974b5e93edSEtienne Carriere 
498b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
499b357d34fSEtienne Carriere 				    struct gpio **out_gpio)
500420a32c5SEtienne Carriere {
501b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
502420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
503420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
504420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
505420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
506420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
507420a32c5SEtienne Carriere 	uint32_t otype = 0;
508420a32c5SEtienne Carriere 	uint32_t pupd = 0;
509420a32c5SEtienne Carriere 	uint32_t mode = 0;
510420a32c5SEtienne Carriere 
511b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
512b357d34fSEtienne Carriere 	if (res)
513b357d34fSEtienne Carriere 		return res;
514420a32c5SEtienne Carriere 
515420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
516420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
517420a32c5SEtienne Carriere 		free(gpio);
518b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
519420a32c5SEtienne Carriere 	}
520420a32c5SEtienne Carriere 
521420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
522420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
523420a32c5SEtienne Carriere 
524420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
525420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
526420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
527420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
528420a32c5SEtienne Carriere 	else
529420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
530420a32c5SEtienne Carriere 
531420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
532420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
533420a32c5SEtienne Carriere 	else
534420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
535420a32c5SEtienne Carriere 
536420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
537420a32c5SEtienne Carriere 		panic();
538420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
539420a32c5SEtienne Carriere 
540420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
541420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
542420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
543420a32c5SEtienne Carriere 
544420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
545420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
546420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
547420a32c5SEtienne Carriere 
548420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
549420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
550420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
551420a32c5SEtienne Carriere 
552420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
553420a32c5SEtienne Carriere 	clk_disable(bank->clock);
554420a32c5SEtienne Carriere 
555420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
556420a32c5SEtienne Carriere 
557b357d34fSEtienne Carriere 	*out_gpio = gpio;
558420a32c5SEtienne Carriere 
559b357d34fSEtienne Carriere 	return TEE_SUCCESS;
560420a32c5SEtienne Carriere }
561420a32c5SEtienne Carriere 
5629818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
5639818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
5649818a481SEtienne Carriere {
5659818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
5669818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
5679818a481SEtienne Carriere 	int len = 0;
5689818a481SEtienne Carriere 
5699818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
5709818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
5719818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
5729818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
5739818a481SEtienne Carriere 
5749818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
5759818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
5769818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
5779818a481SEtienne Carriere 
5789818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
5799818a481SEtienne Carriere }
5809818a481SEtienne Carriere 
5819818a481SEtienne Carriere /*
5829818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
5839818a481SEtienne Carriere  * registered in the GPIO bank link.
5849818a481SEtienne Carriere  */
5859818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
5869818a481SEtienne Carriere {
5879818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
5889818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
5899818a481SEtienne Carriere 
5909818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
5919818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
5929818a481SEtienne Carriere 			return true;
5939818a481SEtienne Carriere 
5949818a481SEtienne Carriere 	return false;
5959818a481SEtienne Carriere }
5969818a481SEtienne Carriere 
5979818a481SEtienne Carriere /* Get GPIO bank information from the DT */
5989818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
5999818a481SEtienne Carriere 				     const void *compat_data __unused,
6009818a481SEtienne Carriere 				     int range_offset,
6019818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
6029818a481SEtienne Carriere {
6039818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
6049818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
6059818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6069818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
6079818a481SEtienne Carriere 	struct clk *clk = NULL;
6089818a481SEtienne Carriere 	size_t blen = 0;
6099818a481SEtienne Carriere 	paddr_t pa = 0;
6109818a481SEtienne Carriere 	int len = 0;
6119818a481SEtienne Carriere 	int i = 0;
6129818a481SEtienne Carriere 
6139818a481SEtienne Carriere 	assert(out_bank);
6149818a481SEtienne Carriere 
6159818a481SEtienne Carriere 	/* Probe deferrable devices first */
6169818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
6179818a481SEtienne Carriere 	if (res)
6189818a481SEtienne Carriere 		return res;
6199818a481SEtienne Carriere 
6209818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
6219818a481SEtienne Carriere 	if (!bank)
6229818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
6239818a481SEtienne Carriere 
6249818a481SEtienne Carriere 	/*
6259818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
6269818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
6279818a481SEtienne Carriere 	 */
6289818a481SEtienne Carriere 	pa = fdt_reg_base_address(fdt, node);
6299818a481SEtienne Carriere 	if (pa == DT_INFO_INVALID_REG)
6309818a481SEtienne Carriere 		panic("missing reg property");
6319818a481SEtienne Carriere 
6329818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
6339818a481SEtienne Carriere 
6349818a481SEtienne Carriere 	blen = fdt_reg_size(fdt, node);
6359818a481SEtienne Carriere 	if (blen == DT_INFO_INVALID_REG_SIZE)
6369818a481SEtienne Carriere 		panic("missing reg size property");
6379818a481SEtienne Carriere 
6389818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
6399818a481SEtienne Carriere 	bank->base = io_pa_or_va_secure(&pa_va, blen);
6409818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
6419818a481SEtienne Carriere 	bank->clock = clk;
642420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
6439818a481SEtienne Carriere 
6449818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
6459818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
6469818a481SEtienne Carriere 	len /= sizeof(*cuint);
6479818a481SEtienne Carriere 	if (len % 4)
6489818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
6499818a481SEtienne Carriere 
6509818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
6519818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
6529818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
6539818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
6549818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
6559818a481SEtienne Carriere 		cuint += 4;
6569818a481SEtienne Carriere 	}
6579818a481SEtienne Carriere 
6589818a481SEtienne Carriere 	*out_bank = bank;
6599818a481SEtienne Carriere 	return TEE_SUCCESS;
6609818a481SEtienne Carriere }
6619818a481SEtienne Carriere 
662be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank)
663be53ee7bSEtienne Carriere {
664be53ee7bSEtienne Carriere 	unsigned int pin = 0;
665be53ee7bSEtienne Carriere 
666be53ee7bSEtienne Carriere 	for (pin = 0; pin <= bank->ngpios; pin++)
667be53ee7bSEtienne Carriere 		stm32_gpio_set_secure_cfg(bank->bank_id, pin, false);
668be53ee7bSEtienne Carriere }
669be53ee7bSEtienne Carriere 
6709818a481SEtienne Carriere /* Parse a pinctrl node to register the GPIO banks it describes */
6710e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
6729818a481SEtienne Carriere 					const void *compat_data)
6739818a481SEtienne Carriere {
6749818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
6759818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6769818a481SEtienne Carriere 	int range_offs = 0;
6779818a481SEtienne Carriere 	int b_node = 0;
6789818a481SEtienne Carriere 	int len = 0;
6799818a481SEtienne Carriere 
6809818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
6819818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
6829818a481SEtienne Carriere 	if (!cuint)
6839818a481SEtienne Carriere 		panic("missing ranges property");
6849818a481SEtienne Carriere 
6859818a481SEtienne Carriere 	len /= sizeof(*cuint);
6869818a481SEtienne Carriere 	if (len == 3)
6879818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
6889818a481SEtienne Carriere 
6899818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
6909818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
6919818a481SEtienne Carriere 		if (cuint) {
6929818a481SEtienne Carriere 			/*
6939818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
6949818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
6959818a481SEtienne Carriere 			 * bank list.
6969818a481SEtienne Carriere 			 */
6979818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
6989818a481SEtienne Carriere 
6999818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
7009818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
7019818a481SEtienne Carriere 				continue;
7029818a481SEtienne Carriere 
7039818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
7049818a481SEtienne Carriere 						 range_offs, &bank);
7059818a481SEtienne Carriere 			if (res)
7069818a481SEtienne Carriere 				return res;
7079818a481SEtienne Carriere 
708420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
709420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
710420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
711420a32c5SEtienne Carriere 			if (res)
712420a32c5SEtienne Carriere 				panic();
713420a32c5SEtienne Carriere 
7149818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
715be53ee7bSEtienne Carriere 
716be53ee7bSEtienne Carriere 			if (IS_ENABLED(CFG_STM32MP13))
717be53ee7bSEtienne Carriere 				set_bank_gpio_non_secure(bank);
7189818a481SEtienne Carriere 		} else {
7199818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
7209818a481SEtienne Carriere 				panic();
7219818a481SEtienne Carriere 		}
7229818a481SEtienne Carriere 	}
7239818a481SEtienne Carriere 
7249818a481SEtienne Carriere 	return TEE_SUCCESS;
7259818a481SEtienne Carriere }
7269818a481SEtienne Carriere 
727a3104caaSEtienne Carriere 
728a3104caaSEtienne Carriere int stm32_get_gpio_count(void *fdt, int pinctrl_node, unsigned int bank)
729a3104caaSEtienne Carriere {
730a3104caaSEtienne Carriere 	int node = 0;
731a3104caaSEtienne Carriere 	const fdt32_t *cuint = NULL;
732a3104caaSEtienne Carriere 
733a3104caaSEtienne Carriere 	fdt_for_each_subnode(node, fdt, pinctrl_node) {
734a3104caaSEtienne Carriere 		if (!fdt_getprop(fdt, node, "gpio-controller", NULL))
735a3104caaSEtienne Carriere 			continue;
736a3104caaSEtienne Carriere 
737a3104caaSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "reg", NULL);
738a3104caaSEtienne Carriere 		if (!cuint)
739a3104caaSEtienne Carriere 			continue;
740a3104caaSEtienne Carriere 
741a3104caaSEtienne Carriere 		if (fdt32_to_cpu(*cuint) != stm32_get_gpio_bank_offset(bank))
742a3104caaSEtienne Carriere 			continue;
743a3104caaSEtienne Carriere 
744a3104caaSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "ngpios", NULL);
745a3104caaSEtienne Carriere 		if (!cuint)
746a3104caaSEtienne Carriere 			panic();
747a3104caaSEtienne Carriere 
748a3104caaSEtienne Carriere 		return (int)fdt32_to_cpu(*cuint);
749a3104caaSEtienne Carriere 	}
750a3104caaSEtienne Carriere 
751a3104caaSEtienne Carriere 	return -1;
752a3104caaSEtienne Carriere }
7534b5e93edSEtienne Carriere 
754077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
755077d486eSEtienne Carriere 			       bool secure)
7564b5e93edSEtienne Carriere {
757077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
75898dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
7594b5e93edSEtienne Carriere 
760077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
761077d486eSEtienne Carriere 		panic();
76298dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
7634b5e93edSEtienne Carriere 
7644b5e93edSEtienne Carriere 	if (secure)
765077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
7664b5e93edSEtienne Carriere 	else
767077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
7684b5e93edSEtienne Carriere 
769c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
77098dfcedaSEtienne Carriere 	clk_disable(bank->clock);
7714b5e93edSEtienne Carriere }
7720e0435e2SEtienne Carriere 
773b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
774b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
775b38386fbSEtienne Carriere {
776b38386fbSEtienne Carriere 	struct stm32_pinctrl_array *ref = conf->priv;
777b38386fbSEtienne Carriere 	struct stm32_pinctrl *p = ref->pinctrl;
778b38386fbSEtienne Carriere 	size_t pin_count = ref->count;
779b38386fbSEtienne Carriere 	size_t n = 0;
780b38386fbSEtienne Carriere 
781b38386fbSEtienne Carriere 	for (n = 0; n < pin_count; n++)
782b38386fbSEtienne Carriere 		set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
783b38386fbSEtienne Carriere 
784b38386fbSEtienne Carriere 	return TEE_SUCCESS;
785b38386fbSEtienne Carriere }
786b38386fbSEtienne Carriere 
787b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
788b38386fbSEtienne Carriere {
789b38386fbSEtienne Carriere 	free(conf);
790b38386fbSEtienne Carriere }
791b38386fbSEtienne Carriere 
792b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
793b38386fbSEtienne Carriere 	.conf_apply = stm32_pinctrl_conf_apply,
794b38386fbSEtienne Carriere 	.conf_free = stm32_pinctrl_conf_free,
795b38386fbSEtienne Carriere };
796b38386fbSEtienne Carriere 
797b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
798b38386fbSEtienne Carriere 
79970ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
80070ac0db5SEtienne Carriere 				 unsigned int *bank, unsigned int *pin,
80170ac0db5SEtienne Carriere 				 unsigned int *count)
80270ac0db5SEtienne Carriere {
80370ac0db5SEtienne Carriere 	size_t conf_index = 0;
80470ac0db5SEtienne Carriere 	size_t pin_count = 0;
80570ac0db5SEtienne Carriere 	size_t n = 0;
80670ac0db5SEtienne Carriere 
80770ac0db5SEtienne Carriere 	assert(count);
80870ac0db5SEtienne Carriere 	if (!pinctrl)
80970ac0db5SEtienne Carriere 		goto out;
81070ac0db5SEtienne Carriere 
81170ac0db5SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
81270ac0db5SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
81370ac0db5SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
81470ac0db5SEtienne Carriere 
81570ac0db5SEtienne Carriere 		/* Consider only the stm32_gpio pins */
81670ac0db5SEtienne Carriere 		if (pinconf->ops != &stm32_pinctrl_ops)
81770ac0db5SEtienne Carriere 			continue;
81870ac0db5SEtienne Carriere 
81970ac0db5SEtienne Carriere 		if (bank || pin) {
82070ac0db5SEtienne Carriere 			for (n = 0; n < ref->count; n++) {
82170ac0db5SEtienne Carriere 				if (bank && pin_count < *count)
82270ac0db5SEtienne Carriere 					bank[pin_count] = ref->pinctrl[n].bank;
82370ac0db5SEtienne Carriere 				if (pin && pin_count < *count)
82470ac0db5SEtienne Carriere 					pin[pin_count] = ref->pinctrl[n].pin;
82570ac0db5SEtienne Carriere 				pin_count++;
82670ac0db5SEtienne Carriere 			}
82770ac0db5SEtienne Carriere 		} else {
82870ac0db5SEtienne Carriere 			pin_count += ref->count;
82970ac0db5SEtienne Carriere 		}
83070ac0db5SEtienne Carriere 	}
83170ac0db5SEtienne Carriere 
83270ac0db5SEtienne Carriere out:
83370ac0db5SEtienne Carriere 	*count = pin_count;
83470ac0db5SEtienne Carriere }
83570ac0db5SEtienne Carriere 
8367f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure)
8377f823a77SEtienne Carriere {
8387f823a77SEtienne Carriere 	size_t conf_index = 0;
8397f823a77SEtienne Carriere 
8407f823a77SEtienne Carriere 	if (!pinctrl)
8417f823a77SEtienne Carriere 		return;
8427f823a77SEtienne Carriere 
8437f823a77SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
8447f823a77SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
8457f823a77SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
8467f823a77SEtienne Carriere 		struct stm32_pinctrl *pc = NULL;
8477f823a77SEtienne Carriere 		size_t n = 0;
8487f823a77SEtienne Carriere 
8497f823a77SEtienne Carriere 		for (n = 0; n < ref->count; n++) {
8507f823a77SEtienne Carriere 			if (pinconf->ops != &stm32_pinctrl_ops)
8517f823a77SEtienne Carriere 				continue;
8527f823a77SEtienne Carriere 
8537f823a77SEtienne Carriere 			pc = ref->pinctrl + n;
8547f823a77SEtienne Carriere 			stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure);
8557f823a77SEtienne Carriere 		}
8567f823a77SEtienne Carriere 	}
8577f823a77SEtienne Carriere }
8587f823a77SEtienne Carriere 
859b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
860b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
861b38386fbSEtienne Carriere 				       void *data __unused,
862b38386fbSEtienne Carriere 				       struct pinconf **out_pinconf)
863b38386fbSEtienne Carriere {
864b38386fbSEtienne Carriere 	struct conf {
865b38386fbSEtienne Carriere 		struct pinconf pinconf;
866b38386fbSEtienne Carriere 		struct stm32_pinctrl_array array_ref;
867b38386fbSEtienne Carriere 	} *loc_conf = NULL;
868b38386fbSEtienne Carriere 	struct stm32_pinctrl *pinctrl = NULL;
869b38386fbSEtienne Carriere 	struct pinconf *pinconf = NULL;
870b38386fbSEtienne Carriere 	const void *fdt = NULL;
871b38386fbSEtienne Carriere 	size_t pin_count = 0;
872b38386fbSEtienne Carriere 	int pinctrl_node = 0;
873b38386fbSEtienne Carriere 	int pinmux_node = 0;
874b38386fbSEtienne Carriere 	int count = 0;
875b38386fbSEtienne Carriere 
876b38386fbSEtienne Carriere 	pinctrl_node = pargs->phandle_node;
877b38386fbSEtienne Carriere 	fdt = pargs->fdt;
878b38386fbSEtienne Carriere 	assert(fdt && pinctrl_node);
879b38386fbSEtienne Carriere 
880b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
881b38386fbSEtienne Carriere 		if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
882b38386fbSEtienne Carriere 			pin_count += (size_t)count / sizeof(uint32_t);
883b38386fbSEtienne Carriere 		else if (count != -FDT_ERR_NOTFOUND)
884b38386fbSEtienne Carriere 			panic();
885b38386fbSEtienne Carriere 	}
886b38386fbSEtienne Carriere 
887b38386fbSEtienne Carriere 	loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
888b38386fbSEtienne Carriere 	if (!loc_conf)
889b38386fbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
890b38386fbSEtienne Carriere 
891b38386fbSEtienne Carriere 	pinconf = &loc_conf->pinconf;
892b38386fbSEtienne Carriere 	pinconf->ops = &stm32_pinctrl_ops;
893b38386fbSEtienne Carriere 	pinconf->priv = &loc_conf->array_ref;
894b38386fbSEtienne Carriere 
895b38386fbSEtienne Carriere 	loc_conf->array_ref.count = pin_count;
896b38386fbSEtienne Carriere 	pinctrl = loc_conf->array_ref.pinctrl;
897b38386fbSEtienne Carriere 
898b38386fbSEtienne Carriere 	count = 0;
899b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
900b38386fbSEtienne Carriere 		int found = 0;
901b38386fbSEtienne Carriere 
902b38386fbSEtienne Carriere 		found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count,
903b38386fbSEtienne Carriere 					     pin_count - count);
904b38386fbSEtienne Carriere 		if (found <= 0 && found > ((int)pin_count - count)) {
905b38386fbSEtienne Carriere 			/* We can't recover from an error here so let's panic */
906b38386fbSEtienne Carriere 			panic();
907b38386fbSEtienne Carriere 		}
908b38386fbSEtienne Carriere 
909b38386fbSEtienne Carriere 		count += found;
910b38386fbSEtienne Carriere 	}
911b38386fbSEtienne Carriere 
912b38386fbSEtienne Carriere 	*out_pinconf = pinconf;
913b38386fbSEtienne Carriere 
914b38386fbSEtienne Carriere 	return TEE_SUCCESS;
915b38386fbSEtienne Carriere }
916b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
917b38386fbSEtienne Carriere 
9180e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
9190e0435e2SEtienne Carriere 				      const void *compat_data)
9200e0435e2SEtienne Carriere {
921b38386fbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
922b38386fbSEtienne Carriere 
9230e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
924b38386fbSEtienne Carriere 	res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
925b38386fbSEtienne Carriere 	if (res)
926b38386fbSEtienne Carriere 		return res;
927b38386fbSEtienne Carriere 
928b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
929b38386fbSEtienne Carriere 	res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
930b38386fbSEtienne Carriere 					(void *)compat_data);
931b38386fbSEtienne Carriere 	if (res)
932b38386fbSEtienne Carriere 		return res;
933b38386fbSEtienne Carriere #endif
934b38386fbSEtienne Carriere 
935b38386fbSEtienne Carriere 	return TEE_SUCCESS;
9360e0435e2SEtienne Carriere }
9370e0435e2SEtienne Carriere 
9380e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
9390e0435e2SEtienne Carriere 	{ .compatible = "st,stm32mp135-pinctrl" },
9400e0435e2SEtienne Carriere 	{ .compatible = "st,stm32mp157-pinctrl" },
9410e0435e2SEtienne Carriere 	{ .compatible = "st,stm32mp157-z-pinctrl" },
9420e0435e2SEtienne Carriere 	{ }
9430e0435e2SEtienne Carriere };
9440e0435e2SEtienne Carriere 
9450e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
9460e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
9470e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
9480e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
9490e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
9500e0435e2SEtienne Carriere };
951