xref: /optee_os/core/drivers/stm32_gpio.c (revision bd03c8c3d70f6af60ac33297e80b10562081893f)
14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
24b5e93edSEtienne Carriere /*
3*bd03c8c3SGatien Chevallier  * Copyright (c) 2017-2024, 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>
15*bd03c8c3SGatien Chevallier #include <drivers/stm32_rif.h>
16*bd03c8c3SGatien Chevallier #include <dt-bindings/gpio/gpio.h>
174b5e93edSEtienne Carriere #include <io.h>
184b5e93edSEtienne Carriere #include <kernel/dt.h>
1965401337SJens Wiklander #include <kernel/boot.h>
204b5e93edSEtienne Carriere #include <kernel/panic.h>
214b5e93edSEtienne Carriere #include <kernel/spinlock.h>
22a2fc83d1SJerome Forissier #include <libfdt.h>
234b5e93edSEtienne Carriere #include <mm/core_memprot.h>
244b5e93edSEtienne Carriere #include <stdbool.h>
2569715ce9SEtienne Carriere #include <stdint.h>
264b5e93edSEtienne Carriere #include <stm32_util.h>
279818a481SEtienne Carriere #include <sys/queue.h>
284b5e93edSEtienne Carriere #include <trace.h>
294b5e93edSEtienne Carriere #include <util.h>
304b5e93edSEtienne Carriere 
311001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO
321001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO
331001585eSEtienne Carriere #endif
341001585eSEtienne Carriere 
354b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
364b5e93edSEtienne Carriere 
375eed568cSGatien Chevallier #define GPIO_MODER_OFFSET	U(0x00)
385eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET	U(0x04)
395eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET	U(0x08)
405eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET	U(0x0c)
415eed568cSGatien Chevallier #define GPIO_IDR_OFFSET		U(0x10)
425eed568cSGatien Chevallier #define GPIO_ODR_OFFSET		U(0x14)
435eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET	U(0x18)
445eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET	U(0x20)
455eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET	U(0x24)
465eed568cSGatien Chevallier #define GPIO_SECR_OFFSET	U(0x30)
47*bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET	U(0x34)
48*bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET	U(0x38)
49*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x)		(U(0x50) + U(0x8) * (x))
50*bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x)		(U(0x54) + U(0x8) * (x))
514b5e93edSEtienne Carriere 
525eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT	U(0x8)
534b5e93edSEtienne Carriere 
54*bd03c8c3SGatien Chevallier /*
55*bd03c8c3SGatien Chevallier  * CIDCFGR register bitfields
56*bd03c8c3SGatien Chevallier  */
57*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK	GENMASK_32(23, 16)
58*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK	GENMASK_32(6, 4)
59*bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK	(_CIDCFGR_CFEN | _CIDCFGR_SEMEN |	\
60*bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SCID_MASK |		\
61*bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SEMWL_MASK)
62*bd03c8c3SGatien Chevallier 
63*bd03c8c3SGatien Chevallier /*
64*bd03c8c3SGatien Chevallier  * PRIVCFGR register bitfields
65*bd03c8c3SGatien Chevallier  */
66*bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK	GENMASK_32(15, 0)
67*bd03c8c3SGatien Chevallier 
68*bd03c8c3SGatien Chevallier /*
69*bd03c8c3SGatien Chevallier  * SECCFGR register bitfields
70*bd03c8c3SGatien Chevallier  */
71*bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK	GENMASK_32(15, 0)
72*bd03c8c3SGatien Chevallier 
73*bd03c8c3SGatien Chevallier /*
74*bd03c8c3SGatien Chevallier  * RCFGLOCKR register bitfields
75*bd03c8c3SGatien Chevallier  */
76*bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK	GENMASK_32(15, 0)
77*bd03c8c3SGatien Chevallier 
78*bd03c8c3SGatien Chevallier /*
79*bd03c8c3SGatien Chevallier  * SEMCR register bitfields
80*bd03c8c3SGatien Chevallier  */
81*bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M	GENMASK_32(6, 4)
82*bd03c8c3SGatien Chevallier 
834b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
844b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
854b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
86729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
874b5e93edSEtienne Carriere 
885eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT	U(12)
894b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
905eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT	U(8)
914b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
924b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
934b5e93edSEtienne Carriere 
949818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0	"GPIOA"
959818a481SEtienne Carriere 
9669715ce9SEtienne Carriere #define GPIO_MODE_INPUT		U(0x0)
9769715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT	U(0x1)
9869715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE	U(0x2)
9969715ce9SEtienne Carriere #define GPIO_MODE_ANALOG	U(0x3)
10069715ce9SEtienne Carriere 
10169715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL	U(0x0)
10269715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN	U(0x1)
10369715ce9SEtienne Carriere 
10469715ce9SEtienne Carriere #define GPIO_OSPEED_LOW		U(0x0)
10569715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM	U(0x1)
10669715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH	U(0x2)
10769715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH	U(0x3)
10869715ce9SEtienne Carriere 
10969715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL	U(0x0)
11069715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP	U(0x1)
11169715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN	U(0x2)
11269715ce9SEtienne Carriere 
11369715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW	U(0x0)
11469715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH	U(0x1)
11569715ce9SEtienne Carriere 
116*bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED	U(3)
117*bd03c8c3SGatien Chevallier 
11869715ce9SEtienne Carriere /*
11969715ce9SEtienne Carriere  * GPIO configuration description structured as single 16bit word
12069715ce9SEtienne Carriere  * for efficient save/restore when GPIO pin suspends or resumes.
12169715ce9SEtienne Carriere  *
12269715ce9SEtienne Carriere  * @mode: One of GPIO_MODE_*
12369715ce9SEtienne Carriere  * @otype: One of GPIO_OTYPE_*
12469715ce9SEtienne Carriere  * @ospeed: One of GPIO_OSPEED_*
12569715ce9SEtienne Carriere  * @pupd: One of GPIO_PUPD_*
12669715ce9SEtienne Carriere  * @od: One of GPIO_OD_*
12769715ce9SEtienne Carriere  * @af: Alternate function numerical ID between 0 and 15
12869715ce9SEtienne Carriere  */
12969715ce9SEtienne Carriere struct gpio_cfg {
13069715ce9SEtienne Carriere 	uint16_t mode:		2;
13169715ce9SEtienne Carriere 	uint16_t otype:		1;
13269715ce9SEtienne Carriere 	uint16_t ospeed:	2;
13369715ce9SEtienne Carriere 	uint16_t pupd:		2;
13469715ce9SEtienne Carriere 	uint16_t od:		1;
13569715ce9SEtienne Carriere 	uint16_t af:		4;
13669715ce9SEtienne Carriere };
13769715ce9SEtienne Carriere 
13869715ce9SEtienne Carriere /*
13969715ce9SEtienne Carriere  * Description of a pin and its muxing
14069715ce9SEtienne Carriere  *
14169715ce9SEtienne Carriere  * @bank: GPIO bank identifier as assigned by the platform
14269715ce9SEtienne Carriere  * @pin: Pin number in the GPIO bank
14369715ce9SEtienne Carriere  * @cfg: Pin configuration
14469715ce9SEtienne Carriere  */
14569715ce9SEtienne Carriere struct stm32_pinctrl {
14669715ce9SEtienne Carriere 	uint8_t bank;
14769715ce9SEtienne Carriere 	uint8_t pin;
14869715ce9SEtienne Carriere 	struct gpio_cfg cfg;
14969715ce9SEtienne Carriere };
15069715ce9SEtienne Carriere 
151b38386fbSEtienne Carriere /*
152b38386fbSEtienne Carriere  * struct stm32_pinctrl_array - Array of pins in a pin control state
153b38386fbSEtienne Carriere  * @count: Number of cells in @pinctrl
154b38386fbSEtienne Carriere  * @pinctrl: Pin control configuration
155b38386fbSEtienne Carriere  */
156b38386fbSEtienne Carriere struct stm32_pinctrl_array {
157b38386fbSEtienne Carriere 	size_t count;
158b38386fbSEtienne Carriere 	struct stm32_pinctrl pinctrl[];
159b38386fbSEtienne Carriere };
160b38386fbSEtienne Carriere 
1619818a481SEtienne Carriere /**
1629818a481SEtienne Carriere  * struct stm32_gpio_bank - GPIO bank instance
1639818a481SEtienne Carriere  *
1649818a481SEtienne Carriere  * @base: base address of the GPIO controller registers.
1659818a481SEtienne Carriere  * @clock: clock identifier.
166420a32c5SEtienne Carriere  * @gpio_chip: GPIO chip reference for that GPIO bank
1679818a481SEtienne Carriere  * @ngpios: number of GPIOs.
1689818a481SEtienne Carriere  * @bank_id: Id of the bank.
1699818a481SEtienne Carriere  * @lock: lock protecting the GPIO bank access.
170*bd03c8c3SGatien Chevallier  * @rif_cfg: RIF configuration data
171*bd03c8c3SGatien Chevallier  * @seccfgr: non-RIF bank secure configuration data
172*bd03c8c3SGatien Chevallier  * @sec_support: True if bank supports pin security protection, else false
173*bd03c8c3SGatien Chevallier  * @ready: True if configuration is applied, else false
174*bd03c8c3SGatien Chevallier  * @is_tdcid: True if OP-TEE runs as Trusted Domain CID
1759818a481SEtienne Carriere  * @link: Link in bank list
1769818a481SEtienne Carriere  */
1779818a481SEtienne Carriere struct stm32_gpio_bank {
1789818a481SEtienne Carriere 	vaddr_t base;
1799818a481SEtienne Carriere 	struct clk *clock;
180420a32c5SEtienne Carriere 	struct gpio_chip gpio_chip;
1819818a481SEtienne Carriere 	unsigned int ngpios;
1829818a481SEtienne Carriere 	unsigned int bank_id;
1839818a481SEtienne Carriere 	unsigned int lock;
184*bd03c8c3SGatien Chevallier 	struct rif_conf_data *rif_cfg;
185*bd03c8c3SGatien Chevallier 	uint32_t seccfgr;
186b4893304SGatien Chevallier 	bool sec_support;
187*bd03c8c3SGatien Chevallier 	bool ready;
188*bd03c8c3SGatien Chevallier 	bool is_tdcid;
1899818a481SEtienne Carriere 	STAILQ_ENTRY(stm32_gpio_bank) link;
1909818a481SEtienne Carriere };
1919818a481SEtienne Carriere 
192b4893304SGatien Chevallier /**
193e569f6adSEtienne Carriere  * Compatibility information of supported banks
194b4893304SGatien Chevallier  *
195b4893304SGatien Chevallier  * @gpioz: True if bank is a GPIOZ bank
196b4893304SGatien Chevallier  * @secure_control: Identify GPIO security bank capability.
197*bd03c8c3SGatien Chevallier  * @secure_extended: Identify RIF presence.
198e569f6adSEtienne Carriere  */
199e569f6adSEtienne Carriere struct bank_compat {
200e569f6adSEtienne Carriere 	bool gpioz;
201b4893304SGatien Chevallier 	bool secure_control;
202*bd03c8c3SGatien Chevallier 	bool secure_extended;
203e569f6adSEtienne Carriere };
204e569f6adSEtienne Carriere 
2054b5e93edSEtienne Carriere static unsigned int gpio_lock;
2064b5e93edSEtienne Carriere 
2079818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
2089818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
2099818a481SEtienne Carriere 
210420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
211420a32c5SEtienne Carriere 
212420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
213420a32c5SEtienne Carriere {
214420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
215420a32c5SEtienne Carriere }
216420a32c5SEtienne Carriere 
217420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(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 	enum gpio_level level = GPIO_LEVEL_HIGH;
222420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
223420a32c5SEtienne Carriere 	unsigned int mode = 0;
224420a32c5SEtienne Carriere 
225420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2262fd102ebSEtienne Carriere 
2272fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2282fd102ebSEtienne Carriere 		panic();
229420a32c5SEtienne Carriere 
230420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
231420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
232420a32c5SEtienne Carriere 
233420a32c5SEtienne Carriere 	switch (mode) {
234420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
235420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
236420a32c5SEtienne Carriere 		break;
237420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
238420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
239420a32c5SEtienne Carriere 		break;
240420a32c5SEtienne Carriere 	default:
241420a32c5SEtienne Carriere 		panic();
242420a32c5SEtienne Carriere 	}
243420a32c5SEtienne Carriere 
244420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
245420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
246420a32c5SEtienne Carriere 	else
247420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
248420a32c5SEtienne Carriere 
249420a32c5SEtienne Carriere 	clk_disable(bank->clock);
250420a32c5SEtienne Carriere 
251420a32c5SEtienne Carriere 	return level;
252420a32c5SEtienne Carriere }
253420a32c5SEtienne Carriere 
254420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
255420a32c5SEtienne Carriere 				 enum gpio_level level)
256420a32c5SEtienne Carriere {
257420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
258420a32c5SEtienne Carriere 
259420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2602fd102ebSEtienne Carriere 
2612fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2622fd102ebSEtienne Carriere 		panic();
263420a32c5SEtienne Carriere 
264420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
265420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
266420a32c5SEtienne Carriere 
267420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
268420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
269420a32c5SEtienne Carriere 	else
270420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
271420a32c5SEtienne Carriere 
272420a32c5SEtienne Carriere 	clk_disable(bank->clock);
273420a32c5SEtienne Carriere }
274420a32c5SEtienne Carriere 
275420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
276420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
277420a32c5SEtienne Carriere {
278420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
279420a32c5SEtienne Carriere 	uint32_t mode = 0;
280420a32c5SEtienne Carriere 
281420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2822fd102ebSEtienne Carriere 
2832fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2842fd102ebSEtienne Carriere 		panic();
285420a32c5SEtienne Carriere 
286420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
287420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
288420a32c5SEtienne Carriere 
289420a32c5SEtienne Carriere 	clk_disable(bank->clock);
290420a32c5SEtienne Carriere 
291420a32c5SEtienne Carriere 	switch (mode) {
292420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
293420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
294420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
295420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
296420a32c5SEtienne Carriere 	default:
297420a32c5SEtienne Carriere 		panic();
298420a32c5SEtienne Carriere 	}
299420a32c5SEtienne Carriere }
300420a32c5SEtienne Carriere 
301420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
302420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
303420a32c5SEtienne Carriere 				     enum gpio_dir direction)
304420a32c5SEtienne Carriere {
305420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
306420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
307420a32c5SEtienne Carriere 	uint32_t mode = 0;
308420a32c5SEtienne Carriere 
309420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
310420a32c5SEtienne Carriere 
311420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
312420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
313420a32c5SEtienne Carriere 	else
314420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
315420a32c5SEtienne Carriere 
3162fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
3172fd102ebSEtienne Carriere 		panic();
318420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
319420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
320420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
321420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
322420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
323420a32c5SEtienne Carriere 	clk_disable(bank->clock);
324420a32c5SEtienne Carriere }
325420a32c5SEtienne Carriere 
326420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused,
327420a32c5SEtienne Carriere 				struct gpio *gpio)
328420a32c5SEtienne Carriere {
329420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
330420a32c5SEtienne Carriere 	free(gpio);
331420a32c5SEtienne Carriere }
332420a32c5SEtienne Carriere 
333420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
334420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
335420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
336420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
337420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
338420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
339420a32c5SEtienne Carriere };
340420a32c5SEtienne Carriere 
341420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
342420a32c5SEtienne Carriere {
343420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
344420a32c5SEtienne Carriere }
345420a32c5SEtienne Carriere 
346077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
3474b5e93edSEtienne Carriere {
348077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
3494b5e93edSEtienne Carriere 
350077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
351077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
352077d486eSEtienne Carriere 			return bank;
353077d486eSEtienne Carriere 
354077d486eSEtienne Carriere 	panic();
355077d486eSEtienne Carriere }
356077d486eSEtienne Carriere 
357077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
358b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin,
359b38386fbSEtienne Carriere 					struct gpio_cfg *cfg)
360077d486eSEtienne Carriere {
361077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
362077d486eSEtienne Carriere 
363077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
364077d486eSEtienne Carriere 		panic();
3654b5e93edSEtienne Carriere 
3664b5e93edSEtienne Carriere 	/*
3674b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
3684b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
3694b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
3704b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
3714b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
3724b5e93edSEtienne Carriere 	 */
373077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
3744b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
3754b5e93edSEtienne Carriere 
376077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
3774b5e93edSEtienne Carriere 
378077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
379077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
3804b5e93edSEtienne Carriere 
381077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
3824b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
3834b5e93edSEtienne Carriere 
384077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
3854b5e93edSEtienne Carriere 
3864b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
387077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
388077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
3894b5e93edSEtienne Carriere 	else
390077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
3914b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
3924b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
3934b5e93edSEtienne Carriere 
394077d486eSEtienne Carriere 	clk_disable(bank->clock);
3954b5e93edSEtienne Carriere }
3964b5e93edSEtienne Carriere 
3974b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
398077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
3994b5e93edSEtienne Carriere {
400077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
40198dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
4024b5e93edSEtienne Carriere 
403077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
404077d486eSEtienne Carriere 		panic();
40598dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
4064b5e93edSEtienne Carriere 
4074b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
408077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
409bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
410bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
4114b5e93edSEtienne Carriere 
4124b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
413077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
414bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
4154b5e93edSEtienne Carriere 
4164b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
417077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
418bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
419bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
4204b5e93edSEtienne Carriere 
4214b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
422077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
423bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
4244b5e93edSEtienne Carriere 
4254b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
4264b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
427077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
428bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
429bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
4304b5e93edSEtienne Carriere 	} else {
4314b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
4324b5e93edSEtienne Carriere 
433077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
434bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
435bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
4364b5e93edSEtienne Carriere 	}
4374b5e93edSEtienne Carriere 
4384b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
439077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
4404b5e93edSEtienne Carriere 
441c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
44298dfcedaSEtienne Carriere 	clk_disable(bank->clock);
4434b5e93edSEtienne Carriere }
4444b5e93edSEtienne Carriere 
4454b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
446b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
4474b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
4484b5e93edSEtienne Carriere {
449b38386fbSEtienne Carriere 	const fdt32_t *cuint = NULL;
450b38386fbSEtienne Carriere 	const fdt32_t *slewrate = NULL;
45110bcbd6cSEtienne Carriere 	int len = 0;
45210bcbd6cSEtienne Carriere 	uint32_t i = 0;
4534b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
4544b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
4554b5e93edSEtienne Carriere 	size_t found = 0;
4564b5e93edSEtienne Carriere 
4574b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
4584b5e93edSEtienne Carriere 	if (!cuint)
4594b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
4604b5e93edSEtienne Carriere 
4614b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
4624b5e93edSEtienne Carriere 	if (slewrate)
4634b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
4644b5e93edSEtienne Carriere 
4654b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
4664b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
4674b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
4684b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
4694b5e93edSEtienne Carriere 
4704b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
47110bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
47210bcbd6cSEtienne Carriere 		uint32_t bank = 0;
47310bcbd6cSEtienne Carriere 		uint32_t pin = 0;
47410bcbd6cSEtienne Carriere 		uint32_t mode = 0;
4754b5e93edSEtienne Carriere 		uint32_t alternate = 0;
476322cf9e3SEtienne Carriere 		uint32_t odata = 0;
4774b5e93edSEtienne Carriere 		bool opendrain = false;
4784b5e93edSEtienne Carriere 
4794b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
4804b5e93edSEtienne Carriere 		cuint++;
4814b5e93edSEtienne Carriere 
4824b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
4834b5e93edSEtienne Carriere 
4844b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
4854b5e93edSEtienne Carriere 
4864b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
4874b5e93edSEtienne Carriere 
4884b5e93edSEtienne Carriere 		switch (mode) {
4894b5e93edSEtienne Carriere 		case 0:
4904b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
4914b5e93edSEtienne Carriere 			break;
4924b5e93edSEtienne Carriere 		case 1:
4934b5e93edSEtienne Carriere 		case 2:
4944b5e93edSEtienne Carriere 		case 3:
4954b5e93edSEtienne Carriere 		case 4:
4964b5e93edSEtienne Carriere 		case 5:
4974b5e93edSEtienne Carriere 		case 6:
4984b5e93edSEtienne Carriere 		case 7:
4994b5e93edSEtienne Carriere 		case 8:
5004b5e93edSEtienne Carriere 		case 9:
5014b5e93edSEtienne Carriere 		case 10:
5024b5e93edSEtienne Carriere 		case 11:
5034b5e93edSEtienne Carriere 		case 12:
5044b5e93edSEtienne Carriere 		case 13:
5054b5e93edSEtienne Carriere 		case 14:
5064b5e93edSEtienne Carriere 		case 15:
5074b5e93edSEtienne Carriere 		case 16:
5084b5e93edSEtienne Carriere 			alternate = mode - 1U;
5094b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
5104b5e93edSEtienne Carriere 			break;
5114b5e93edSEtienne Carriere 		case 17:
5124b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
5134b5e93edSEtienne Carriere 			break;
5144b5e93edSEtienne Carriere 		default:
5154b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
5164b5e93edSEtienne Carriere 			break;
5174b5e93edSEtienne Carriere 		}
5184b5e93edSEtienne Carriere 
5194b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
5204b5e93edSEtienne Carriere 			opendrain = true;
5214b5e93edSEtienne Carriere 
522322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-high", NULL) &&
523322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
524322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
525322cf9e3SEtienne Carriere 			odata = 1;
526322cf9e3SEtienne Carriere 		}
527322cf9e3SEtienne Carriere 
528322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-low", NULL) &&
529322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
530322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
531322cf9e3SEtienne Carriere 			odata = 0;
532322cf9e3SEtienne Carriere 		}
533322cf9e3SEtienne Carriere 
5344b5e93edSEtienne Carriere 		if (found < count) {
5354b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
5364b5e93edSEtienne Carriere 
5374b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
5384b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
539b38386fbSEtienne Carriere 			ref->cfg.mode = mode;
540b38386fbSEtienne Carriere 			if (opendrain)
541b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
542b38386fbSEtienne Carriere 			else
543b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
544b38386fbSEtienne Carriere 			ref->cfg.ospeed = speed;
545b38386fbSEtienne Carriere 			ref->cfg.pupd = pull;
546b38386fbSEtienne Carriere 			ref->cfg.od = odata;
547b38386fbSEtienne Carriere 			ref->cfg.af = alternate;
5484b5e93edSEtienne Carriere 		}
5494b5e93edSEtienne Carriere 
5504b5e93edSEtienne Carriere 		found++;
5514b5e93edSEtienne Carriere 	}
5524b5e93edSEtienne Carriere 
5534b5e93edSEtienne Carriere 	return (int)found;
5544b5e93edSEtienne Carriere }
5554b5e93edSEtienne Carriere 
556b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
557b357d34fSEtienne Carriere 				    struct gpio **out_gpio)
558420a32c5SEtienne Carriere {
559b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
560420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
561420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
562420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
563420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
564420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
565420a32c5SEtienne Carriere 	uint32_t otype = 0;
566420a32c5SEtienne Carriere 	uint32_t pupd = 0;
567420a32c5SEtienne Carriere 	uint32_t mode = 0;
568420a32c5SEtienne Carriere 
569b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
570b357d34fSEtienne Carriere 	if (res)
571b357d34fSEtienne Carriere 		return res;
572420a32c5SEtienne Carriere 
573420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
574420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
575420a32c5SEtienne Carriere 		free(gpio);
576b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
577420a32c5SEtienne Carriere 	}
578420a32c5SEtienne Carriere 
579420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
580420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
581420a32c5SEtienne Carriere 
582420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
583420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
584420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
585420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
586420a32c5SEtienne Carriere 	else
587420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
588420a32c5SEtienne Carriere 
589420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
590420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
591420a32c5SEtienne Carriere 	else
592420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
593420a32c5SEtienne Carriere 
594420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
595420a32c5SEtienne Carriere 		panic();
596420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
597420a32c5SEtienne Carriere 
598420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
599420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
600420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
601420a32c5SEtienne Carriere 
602420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
603420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
604420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
605420a32c5SEtienne Carriere 
606420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
607420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
608420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
609420a32c5SEtienne Carriere 
610420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
611420a32c5SEtienne Carriere 	clk_disable(bank->clock);
612420a32c5SEtienne Carriere 
613420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
614420a32c5SEtienne Carriere 
615b357d34fSEtienne Carriere 	*out_gpio = gpio;
616420a32c5SEtienne Carriere 
617b357d34fSEtienne Carriere 	return TEE_SUCCESS;
618420a32c5SEtienne Carriere }
619420a32c5SEtienne Carriere 
6209818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
6219818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
6229818a481SEtienne Carriere {
6239818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
6249818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6259818a481SEtienne Carriere 	int len = 0;
6269818a481SEtienne Carriere 
6279818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
6289818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
6299818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
6309818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
6319818a481SEtienne Carriere 
6329818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
6339818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
6349818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
6359818a481SEtienne Carriere 
6369818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
6379818a481SEtienne Carriere }
6389818a481SEtienne Carriere 
6399818a481SEtienne Carriere /*
6409818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
6419818a481SEtienne Carriere  * registered in the GPIO bank link.
6429818a481SEtienne Carriere  */
6439818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
6449818a481SEtienne Carriere {
6459818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
6469818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
6479818a481SEtienne Carriere 
6489818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
6499818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
6509818a481SEtienne Carriere 			return true;
6519818a481SEtienne Carriere 
6529818a481SEtienne Carriere 	return false;
6539818a481SEtienne Carriere }
6549818a481SEtienne Carriere 
655*bd03c8c3SGatien Chevallier static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank)
656*bd03c8c3SGatien Chevallier {
657*bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
658*bd03c8c3SGatien Chevallier 	uint32_t cidcfgr = 0;
659*bd03c8c3SGatien Chevallier 	unsigned int i = 0;
660*bd03c8c3SGatien Chevallier 
661*bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
662*bd03c8c3SGatien Chevallier 		return TEE_SUCCESS;
663*bd03c8c3SGatien Chevallier 
664*bd03c8c3SGatien Chevallier 	if (clk_enable(bank->clock))
665*bd03c8c3SGatien Chevallier 		panic();
666*bd03c8c3SGatien Chevallier 
667*bd03c8c3SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++) {
668*bd03c8c3SGatien Chevallier 		if (!(BIT(i) & bank->rif_cfg->access_mask[0]))
669*bd03c8c3SGatien Chevallier 			continue;
670*bd03c8c3SGatien Chevallier 
671*bd03c8c3SGatien Chevallier 		/*
672*bd03c8c3SGatien Chevallier 		 * When TDCID, OP-TEE should be the one to set the CID filtering
673*bd03c8c3SGatien Chevallier 		 * configuration. Clearing previous configuration prevents
674*bd03c8c3SGatien Chevallier 		 * undesired events during the only legitimate configuration.
675*bd03c8c3SGatien Chevallier 		 */
676*bd03c8c3SGatien Chevallier 		if (bank->is_tdcid)
677*bd03c8c3SGatien Chevallier 			io_clrbits32(bank->base + GPIO_CIDCFGR(i),
678*bd03c8c3SGatien Chevallier 				     GPIO_CIDCFGR_CONF_MASK);
679*bd03c8c3SGatien Chevallier 
680*bd03c8c3SGatien Chevallier 		cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i));
681*bd03c8c3SGatien Chevallier 
682*bd03c8c3SGatien Chevallier 		/* Check if the controller is in semaphore mode */
683*bd03c8c3SGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
684*bd03c8c3SGatien Chevallier 			continue;
685*bd03c8c3SGatien Chevallier 
686*bd03c8c3SGatien Chevallier 		/* If not TDCID, we want to acquire semaphores assigned to us */
687*bd03c8c3SGatien Chevallier 		res = stm32_rif_acquire_semaphore(bank->base + GPIO_SEMCR(i),
688*bd03c8c3SGatien Chevallier 						  GPIO_MAX_CID_SUPPORTED);
689*bd03c8c3SGatien Chevallier 		if (res) {
690*bd03c8c3SGatien Chevallier 			EMSG("Could not acquire semaphore for pin %c%u",
691*bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id, i);
692*bd03c8c3SGatien Chevallier 			goto out;
693*bd03c8c3SGatien Chevallier 		}
694*bd03c8c3SGatien Chevallier 	}
695*bd03c8c3SGatien Chevallier 
696*bd03c8c3SGatien Chevallier 	/* Security and privilege RIF configuration */
697*bd03c8c3SGatien Chevallier 	io_clrsetbits32(bank->base + GPIO_PRIVCFGR_OFFSET, GPIO_PRIVCFGR_MASK,
698*bd03c8c3SGatien Chevallier 			bank->rif_cfg->priv_conf[0]);
699*bd03c8c3SGatien Chevallier 	io_clrsetbits32(bank->base + GPIO_SECR_OFFSET, GPIO_SECCFGR_MASK,
700*bd03c8c3SGatien Chevallier 			bank->rif_cfg->sec_conf[0]);
701*bd03c8c3SGatien Chevallier 
702*bd03c8c3SGatien Chevallier 	if (!bank->is_tdcid) {
703*bd03c8c3SGatien Chevallier 		res = TEE_SUCCESS;
704*bd03c8c3SGatien Chevallier 		goto out;
705*bd03c8c3SGatien Chevallier 	}
706*bd03c8c3SGatien Chevallier 
707*bd03c8c3SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++) {
708*bd03c8c3SGatien Chevallier 		if (!(BIT(i) & bank->rif_cfg->access_mask[0]))
709*bd03c8c3SGatien Chevallier 			continue;
710*bd03c8c3SGatien Chevallier 
711*bd03c8c3SGatien Chevallier 		io_clrsetbits32(bank->base + GPIO_CIDCFGR(i),
712*bd03c8c3SGatien Chevallier 				GPIO_CIDCFGR_CONF_MASK,
713*bd03c8c3SGatien Chevallier 				bank->rif_cfg->cid_confs[i]);
714*bd03c8c3SGatien Chevallier 
715*bd03c8c3SGatien Chevallier 		cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i));
716*bd03c8c3SGatien Chevallier 
717*bd03c8c3SGatien Chevallier 		/*
718*bd03c8c3SGatien Chevallier 		 * Take semaphore if the resource is in semaphore mode
719*bd03c8c3SGatien Chevallier 		 * and secured.
720*bd03c8c3SGatien Chevallier 		 */
721*bd03c8c3SGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1) ||
722*bd03c8c3SGatien Chevallier 		    !(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) {
723*bd03c8c3SGatien Chevallier 			res = stm32_rif_release_semaphore(bank->base +
724*bd03c8c3SGatien Chevallier 				GPIO_SEMCR(i),
725*bd03c8c3SGatien Chevallier 				GPIO_MAX_CID_SUPPORTED);
726*bd03c8c3SGatien Chevallier 			if (res) {
727*bd03c8c3SGatien Chevallier 				EMSG("Could not release semaphore for pin %c%u",
728*bd03c8c3SGatien Chevallier 				     'A' + bank->bank_id, i);
729*bd03c8c3SGatien Chevallier 				goto out;
730*bd03c8c3SGatien Chevallier 			}
731*bd03c8c3SGatien Chevallier 		} else {
732*bd03c8c3SGatien Chevallier 			res = stm32_rif_acquire_semaphore(bank->base +
733*bd03c8c3SGatien Chevallier 				GPIO_SEMCR(i),
734*bd03c8c3SGatien Chevallier 				GPIO_MAX_CID_SUPPORTED);
735*bd03c8c3SGatien Chevallier 			if (res) {
736*bd03c8c3SGatien Chevallier 				EMSG("Could not acquire semaphore for pin %c%u",
737*bd03c8c3SGatien Chevallier 				     'A' + bank->bank_id, i);
738*bd03c8c3SGatien Chevallier 				goto out;
739*bd03c8c3SGatien Chevallier 			}
740*bd03c8c3SGatien Chevallier 		}
741*bd03c8c3SGatien Chevallier 	}
742*bd03c8c3SGatien Chevallier 
743*bd03c8c3SGatien Chevallier 	/*
744*bd03c8c3SGatien Chevallier 	 * Lock RIF configuration if configured. This cannot be undone until
745*bd03c8c3SGatien Chevallier 	 * next reset.
746*bd03c8c3SGatien Chevallier 	 */
747*bd03c8c3SGatien Chevallier 	io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET,
748*bd03c8c3SGatien Chevallier 		     bank->rif_cfg->lock_conf[0]);
749*bd03c8c3SGatien Chevallier 
750*bd03c8c3SGatien Chevallier 	if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) {
751*bd03c8c3SGatien Chevallier 		/* Check that RIF config are applied, panic otherwise */
752*bd03c8c3SGatien Chevallier 		if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) &
753*bd03c8c3SGatien Chevallier 		     bank->rif_cfg->access_mask[0]) !=
754*bd03c8c3SGatien Chevallier 		    bank->rif_cfg->priv_conf[0]) {
755*bd03c8c3SGatien Chevallier 			EMSG("GPIO bank%c priv conf is incorrect",
756*bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
757*bd03c8c3SGatien Chevallier 			panic();
758*bd03c8c3SGatien Chevallier 		}
759*bd03c8c3SGatien Chevallier 
760*bd03c8c3SGatien Chevallier 		if ((io_read32(bank->base + GPIO_SECR_OFFSET) &
761*bd03c8c3SGatien Chevallier 		     bank->rif_cfg->access_mask[0]) !=
762*bd03c8c3SGatien Chevallier 		    bank->rif_cfg->sec_conf[0]) {
763*bd03c8c3SGatien Chevallier 			EMSG("GPIO bank %c sec conf is incorrect",
764*bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
765*bd03c8c3SGatien Chevallier 			panic();
766*bd03c8c3SGatien Chevallier 		}
767*bd03c8c3SGatien Chevallier 	}
768*bd03c8c3SGatien Chevallier 
769*bd03c8c3SGatien Chevallier 	res = TEE_SUCCESS;
770*bd03c8c3SGatien Chevallier out:
771*bd03c8c3SGatien Chevallier 	clk_disable(bank->clock);
772*bd03c8c3SGatien Chevallier 
773*bd03c8c3SGatien Chevallier 	return res;
774*bd03c8c3SGatien Chevallier }
775*bd03c8c3SGatien Chevallier 
776*bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank,
777*bd03c8c3SGatien Chevallier 				      const void *fdt, int node)
778*bd03c8c3SGatien Chevallier {
779*bd03c8c3SGatien Chevallier 	unsigned int i = 0;
780*bd03c8c3SGatien Chevallier 	unsigned int nb_rif_conf = 0;
781*bd03c8c3SGatien Chevallier 	int lenp = 0;
782*bd03c8c3SGatien Chevallier 	const fdt32_t *cuint = NULL;
783*bd03c8c3SGatien Chevallier 
784*bd03c8c3SGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
785*bd03c8c3SGatien Chevallier 	if (!cuint) {
786*bd03c8c3SGatien Chevallier 		DMSG("No RIF configuration available");
787*bd03c8c3SGatien Chevallier 		return;
788*bd03c8c3SGatien Chevallier 	}
789*bd03c8c3SGatien Chevallier 
790*bd03c8c3SGatien Chevallier 	bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg));
791*bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
792*bd03c8c3SGatien Chevallier 		panic();
793*bd03c8c3SGatien Chevallier 
794*bd03c8c3SGatien Chevallier 	bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t));
795*bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->sec_conf)
796*bd03c8c3SGatien Chevallier 		panic();
797*bd03c8c3SGatien Chevallier 
798*bd03c8c3SGatien Chevallier 	nb_rif_conf = (unsigned int)(lenp / sizeof(uint32_t));
799*bd03c8c3SGatien Chevallier 	assert(nb_rif_conf <= bank->ngpios);
800*bd03c8c3SGatien Chevallier 
801*bd03c8c3SGatien Chevallier 	bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t));
802*bd03c8c3SGatien Chevallier 	bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t));
803*bd03c8c3SGatien Chevallier 	bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t));
804*bd03c8c3SGatien Chevallier 	bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t));
805*bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask ||
806*bd03c8c3SGatien Chevallier 	    !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf)
807*bd03c8c3SGatien Chevallier 		panic("Missing memory capacity for GPIOS RIF configuration");
808*bd03c8c3SGatien Chevallier 
809*bd03c8c3SGatien Chevallier 	for (i = 0; i < nb_rif_conf; i++)
810*bd03c8c3SGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg,
811*bd03c8c3SGatien Chevallier 				    GPIO_MAX_CID_SUPPORTED, bank->ngpios);
812*bd03c8c3SGatien Chevallier }
813*bd03c8c3SGatien Chevallier 
8149818a481SEtienne Carriere /* Get GPIO bank information from the DT */
8159818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
816e569f6adSEtienne Carriere 				     const void *compat_data,
8179818a481SEtienne Carriere 				     int range_offset,
8189818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
8199818a481SEtienne Carriere {
820e569f6adSEtienne Carriere 	const struct bank_compat *compat = compat_data;
8219818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
8229818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
8239818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
8249818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
8259818a481SEtienne Carriere 	struct clk *clk = NULL;
8269818a481SEtienne Carriere 	size_t blen = 0;
8279818a481SEtienne Carriere 	paddr_t pa = 0;
8289818a481SEtienne Carriere 	int len = 0;
8299818a481SEtienne Carriere 	int i = 0;
8309818a481SEtienne Carriere 
8319818a481SEtienne Carriere 	assert(out_bank);
8329818a481SEtienne Carriere 
8339818a481SEtienne Carriere 	/* Probe deferrable devices first */
8349818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
8359818a481SEtienne Carriere 	if (res)
8369818a481SEtienne Carriere 		return res;
8379818a481SEtienne Carriere 
8389818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
8399818a481SEtienne Carriere 	if (!bank)
8409818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
8419818a481SEtienne Carriere 
842*bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
843*bd03c8c3SGatien Chevallier 		res = stm32_rifsc_check_tdcid(&bank->is_tdcid);
844*bd03c8c3SGatien Chevallier 		if (res) {
845*bd03c8c3SGatien Chevallier 			free(bank);
846*bd03c8c3SGatien Chevallier 			return res;
847*bd03c8c3SGatien Chevallier 		}
848*bd03c8c3SGatien Chevallier 	}
849*bd03c8c3SGatien Chevallier 
8509818a481SEtienne Carriere 	/*
8519818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
8529818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
8539818a481SEtienne Carriere 	 */
8549818a481SEtienne Carriere 	pa = fdt_reg_base_address(fdt, node);
8559818a481SEtienne Carriere 	if (pa == DT_INFO_INVALID_REG)
8569818a481SEtienne Carriere 		panic("missing reg property");
8579818a481SEtienne Carriere 
8589818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
8599818a481SEtienne Carriere 
8609818a481SEtienne Carriere 	blen = fdt_reg_size(fdt, node);
8619818a481SEtienne Carriere 	if (blen == DT_INFO_INVALID_REG_SIZE)
8629818a481SEtienne Carriere 		panic("missing reg size property");
8639818a481SEtienne Carriere 
8649818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
8659818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
8669818a481SEtienne Carriere 	bank->clock = clk;
867420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
868b4893304SGatien Chevallier 	bank->sec_support = compat->secure_control;
8699818a481SEtienne Carriere 
8709818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
8719818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
8729818a481SEtienne Carriere 	len /= sizeof(*cuint);
8739818a481SEtienne Carriere 	if (len % 4)
8749818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
8759818a481SEtienne Carriere 
8769818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
8779818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
8789818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
8799818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
8809818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
8819818a481SEtienne Carriere 		cuint += 4;
8829818a481SEtienne Carriere 	}
8839818a481SEtienne Carriere 
884*bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
885*bd03c8c3SGatien Chevallier 		/* RIF configuration */
886*bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
887*bd03c8c3SGatien Chevallier 
888*bd03c8c3SGatien Chevallier 		stm32_parse_gpio_rif_conf(bank, fdt, node);
889*bd03c8c3SGatien Chevallier 	} else if (bank->sec_support) {
890*bd03c8c3SGatien Chevallier 		/* Secure configuration */
891*bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
892*bd03c8c3SGatien Chevallier 		cuint = fdt_getprop(fdt, node, "st,protreg", NULL);
893*bd03c8c3SGatien Chevallier 		if (cuint)
894*bd03c8c3SGatien Chevallier 			bank->seccfgr = fdt32_to_cpu(*cuint);
895*bd03c8c3SGatien Chevallier 		else
896*bd03c8c3SGatien Chevallier 			DMSG("GPIO bank %c assigned to non-secure",
897*bd03c8c3SGatien Chevallier 			     bank->bank_id + 'A');
898*bd03c8c3SGatien Chevallier 	} else {
899*bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_nsec(&pa_va, blen);
900*bd03c8c3SGatien Chevallier 	}
901*bd03c8c3SGatien Chevallier 
902e569f6adSEtienne Carriere 	if (compat->gpioz)
903e569f6adSEtienne Carriere 		stm32mp_register_gpioz_pin_count(bank->ngpios);
904e569f6adSEtienne Carriere 
9059818a481SEtienne Carriere 	*out_bank = bank;
906*bd03c8c3SGatien Chevallier 
9079818a481SEtienne Carriere 	return TEE_SUCCESS;
9089818a481SEtienne Carriere }
9099818a481SEtienne Carriere 
910*bd03c8c3SGatien Chevallier /* Parse a pinctrl node to register the GPIO banks it describes */
9110e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
9129818a481SEtienne Carriere 					const void *compat_data)
9139818a481SEtienne Carriere {
9149818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
9159818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
9169818a481SEtienne Carriere 	int range_offs = 0;
9179818a481SEtienne Carriere 	int b_node = 0;
9189818a481SEtienne Carriere 	int len = 0;
9199818a481SEtienne Carriere 
9209818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
9219818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
9229818a481SEtienne Carriere 	if (!cuint)
9239818a481SEtienne Carriere 		panic("missing ranges property");
9249818a481SEtienne Carriere 
9259818a481SEtienne Carriere 	len /= sizeof(*cuint);
9269818a481SEtienne Carriere 	if (len == 3)
9279818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
9289818a481SEtienne Carriere 
9299818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
9309818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
9319818a481SEtienne Carriere 		if (cuint) {
9329818a481SEtienne Carriere 			/*
9339818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
9349818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
9359818a481SEtienne Carriere 			 * bank list.
9369818a481SEtienne Carriere 			 */
9379818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
9389818a481SEtienne Carriere 
9399818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
9409818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
9419818a481SEtienne Carriere 				continue;
9429818a481SEtienne Carriere 
9439818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
9449818a481SEtienne Carriere 						 range_offs, &bank);
9459818a481SEtienne Carriere 			if (res)
9469818a481SEtienne Carriere 				return res;
9479818a481SEtienne Carriere 
948420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
949420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
950420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
951420a32c5SEtienne Carriere 			if (res)
952420a32c5SEtienne Carriere 				panic();
953420a32c5SEtienne Carriere 
9549818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
9559818a481SEtienne Carriere 		} else {
9569818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
9579818a481SEtienne Carriere 				panic();
9589818a481SEtienne Carriere 		}
9599818a481SEtienne Carriere 	}
9609818a481SEtienne Carriere 
9619818a481SEtienne Carriere 	return TEE_SUCCESS;
9629818a481SEtienne Carriere }
9639818a481SEtienne Carriere 
964077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
965077d486eSEtienne Carriere 			       bool secure)
9664b5e93edSEtienne Carriere {
967077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
96898dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
9694b5e93edSEtienne Carriere 
970077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
971077d486eSEtienne Carriere 		panic();
97298dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
9734b5e93edSEtienne Carriere 
9744b5e93edSEtienne Carriere 	if (secure)
975077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
9764b5e93edSEtienne Carriere 	else
977077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
9784b5e93edSEtienne Carriere 
979c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
98098dfcedaSEtienne Carriere 	clk_disable(bank->clock);
9814b5e93edSEtienne Carriere }
9820e0435e2SEtienne Carriere 
983b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
984b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
985b38386fbSEtienne Carriere {
986b38386fbSEtienne Carriere 	struct stm32_pinctrl_array *ref = conf->priv;
987b38386fbSEtienne Carriere 	struct stm32_pinctrl *p = ref->pinctrl;
988b38386fbSEtienne Carriere 	size_t pin_count = ref->count;
989b38386fbSEtienne Carriere 	size_t n = 0;
990b38386fbSEtienne Carriere 
991b38386fbSEtienne Carriere 	for (n = 0; n < pin_count; n++)
992b38386fbSEtienne Carriere 		set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
993b38386fbSEtienne Carriere 
994b38386fbSEtienne Carriere 	return TEE_SUCCESS;
995b38386fbSEtienne Carriere }
996b38386fbSEtienne Carriere 
997b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
998b38386fbSEtienne Carriere {
999b38386fbSEtienne Carriere 	free(conf);
1000b38386fbSEtienne Carriere }
1001b38386fbSEtienne Carriere 
1002b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
1003b38386fbSEtienne Carriere 	.conf_apply = stm32_pinctrl_conf_apply,
1004b38386fbSEtienne Carriere 	.conf_free = stm32_pinctrl_conf_free,
1005b38386fbSEtienne Carriere };
1006b38386fbSEtienne Carriere 
1007b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
1008b38386fbSEtienne Carriere 
100970ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
101070ac0db5SEtienne Carriere 				 unsigned int *bank, unsigned int *pin,
101170ac0db5SEtienne Carriere 				 unsigned int *count)
101270ac0db5SEtienne Carriere {
101370ac0db5SEtienne Carriere 	size_t conf_index = 0;
101470ac0db5SEtienne Carriere 	size_t pin_count = 0;
101570ac0db5SEtienne Carriere 	size_t n = 0;
101670ac0db5SEtienne Carriere 
101770ac0db5SEtienne Carriere 	assert(count);
101870ac0db5SEtienne Carriere 	if (!pinctrl)
101970ac0db5SEtienne Carriere 		goto out;
102070ac0db5SEtienne Carriere 
102170ac0db5SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
102270ac0db5SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
102370ac0db5SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
102470ac0db5SEtienne Carriere 
102570ac0db5SEtienne Carriere 		/* Consider only the stm32_gpio pins */
102670ac0db5SEtienne Carriere 		if (pinconf->ops != &stm32_pinctrl_ops)
102770ac0db5SEtienne Carriere 			continue;
102870ac0db5SEtienne Carriere 
102970ac0db5SEtienne Carriere 		if (bank || pin) {
103070ac0db5SEtienne Carriere 			for (n = 0; n < ref->count; n++) {
103170ac0db5SEtienne Carriere 				if (bank && pin_count < *count)
103270ac0db5SEtienne Carriere 					bank[pin_count] = ref->pinctrl[n].bank;
103370ac0db5SEtienne Carriere 				if (pin && pin_count < *count)
103470ac0db5SEtienne Carriere 					pin[pin_count] = ref->pinctrl[n].pin;
103570ac0db5SEtienne Carriere 				pin_count++;
103670ac0db5SEtienne Carriere 			}
103770ac0db5SEtienne Carriere 		} else {
103870ac0db5SEtienne Carriere 			pin_count += ref->count;
103970ac0db5SEtienne Carriere 		}
104070ac0db5SEtienne Carriere 	}
104170ac0db5SEtienne Carriere 
104270ac0db5SEtienne Carriere out:
104370ac0db5SEtienne Carriere 	*count = pin_count;
104470ac0db5SEtienne Carriere }
104570ac0db5SEtienne Carriere 
10467f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure)
10477f823a77SEtienne Carriere {
10487f823a77SEtienne Carriere 	size_t conf_index = 0;
10497f823a77SEtienne Carriere 
10507f823a77SEtienne Carriere 	if (!pinctrl)
10517f823a77SEtienne Carriere 		return;
10527f823a77SEtienne Carriere 
10537f823a77SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
10547f823a77SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
10557f823a77SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
10567f823a77SEtienne Carriere 		struct stm32_pinctrl *pc = NULL;
10577f823a77SEtienne Carriere 		size_t n = 0;
10587f823a77SEtienne Carriere 
10597f823a77SEtienne Carriere 		for (n = 0; n < ref->count; n++) {
10607f823a77SEtienne Carriere 			if (pinconf->ops != &stm32_pinctrl_ops)
10617f823a77SEtienne Carriere 				continue;
10627f823a77SEtienne Carriere 
10637f823a77SEtienne Carriere 			pc = ref->pinctrl + n;
10647f823a77SEtienne Carriere 			stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure);
10657f823a77SEtienne Carriere 		}
10667f823a77SEtienne Carriere 	}
10677f823a77SEtienne Carriere }
10687f823a77SEtienne Carriere 
1069b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
1070b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
1071b38386fbSEtienne Carriere 				       void *data __unused,
1072b38386fbSEtienne Carriere 				       struct pinconf **out_pinconf)
1073b38386fbSEtienne Carriere {
1074b38386fbSEtienne Carriere 	struct conf {
1075b38386fbSEtienne Carriere 		struct pinconf pinconf;
1076b38386fbSEtienne Carriere 		struct stm32_pinctrl_array array_ref;
1077b38386fbSEtienne Carriere 	} *loc_conf = NULL;
1078b38386fbSEtienne Carriere 	struct stm32_pinctrl *pinctrl = NULL;
1079b38386fbSEtienne Carriere 	struct pinconf *pinconf = NULL;
1080b38386fbSEtienne Carriere 	const void *fdt = NULL;
1081b38386fbSEtienne Carriere 	size_t pin_count = 0;
1082b38386fbSEtienne Carriere 	int pinctrl_node = 0;
1083b38386fbSEtienne Carriere 	int pinmux_node = 0;
1084b38386fbSEtienne Carriere 	int count = 0;
1085b38386fbSEtienne Carriere 
1086b38386fbSEtienne Carriere 	pinctrl_node = pargs->phandle_node;
1087b38386fbSEtienne Carriere 	fdt = pargs->fdt;
1088b38386fbSEtienne Carriere 	assert(fdt && pinctrl_node);
1089b38386fbSEtienne Carriere 
1090b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1091b38386fbSEtienne Carriere 		if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
1092b38386fbSEtienne Carriere 			pin_count += (size_t)count / sizeof(uint32_t);
1093b38386fbSEtienne Carriere 		else if (count != -FDT_ERR_NOTFOUND)
1094b38386fbSEtienne Carriere 			panic();
1095b38386fbSEtienne Carriere 	}
1096b38386fbSEtienne Carriere 
1097b38386fbSEtienne Carriere 	loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
1098b38386fbSEtienne Carriere 	if (!loc_conf)
1099b38386fbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
1100b38386fbSEtienne Carriere 
1101b38386fbSEtienne Carriere 	pinconf = &loc_conf->pinconf;
1102b38386fbSEtienne Carriere 	pinconf->ops = &stm32_pinctrl_ops;
1103b38386fbSEtienne Carriere 	pinconf->priv = &loc_conf->array_ref;
1104b38386fbSEtienne Carriere 
1105b38386fbSEtienne Carriere 	loc_conf->array_ref.count = pin_count;
1106b38386fbSEtienne Carriere 	pinctrl = loc_conf->array_ref.pinctrl;
1107b38386fbSEtienne Carriere 
1108b38386fbSEtienne Carriere 	count = 0;
1109b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1110b38386fbSEtienne Carriere 		int found = 0;
1111b38386fbSEtienne Carriere 
1112b38386fbSEtienne Carriere 		found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count,
1113b38386fbSEtienne Carriere 					     pin_count - count);
1114b38386fbSEtienne Carriere 		if (found <= 0 && found > ((int)pin_count - count)) {
1115b38386fbSEtienne Carriere 			/* We can't recover from an error here so let's panic */
1116b38386fbSEtienne Carriere 			panic();
1117b38386fbSEtienne Carriere 		}
1118b38386fbSEtienne Carriere 
1119b38386fbSEtienne Carriere 		count += found;
1120b38386fbSEtienne Carriere 	}
1121b38386fbSEtienne Carriere 
1122b38386fbSEtienne Carriere 	*out_pinconf = pinconf;
1123b38386fbSEtienne Carriere 
1124b38386fbSEtienne Carriere 	return TEE_SUCCESS;
1125b38386fbSEtienne Carriere }
1126b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
1127b38386fbSEtienne Carriere 
1128*bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank)
1129*bd03c8c3SGatien Chevallier {
1130*bd03c8c3SGatien Chevallier 	if (bank->sec_support) {
1131*bd03c8c3SGatien Chevallier 		clk_enable(bank->clock);
1132*bd03c8c3SGatien Chevallier 		io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr);
1133*bd03c8c3SGatien Chevallier 		clk_disable(bank->clock);
1134*bd03c8c3SGatien Chevallier 	}
1135*bd03c8c3SGatien Chevallier }
1136*bd03c8c3SGatien Chevallier 
1137*bd03c8c3SGatien Chevallier /*
1138*bd03c8c3SGatien Chevallier  * Several pinctrl nodes can be probed. Their bank will be put in the unique
1139*bd03c8c3SGatien Chevallier  * bank_list. To avoid multiple configuration set for a bank when looping
1140*bd03c8c3SGatien Chevallier  * over each bank in the bank list, ready is set to true when a bank is
1141*bd03c8c3SGatien Chevallier  * configured. Therefore, during other bank probes, the configuration won't
1142*bd03c8c3SGatien Chevallier  * be set again.
1143*bd03c8c3SGatien Chevallier  */
1144*bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void)
1145*bd03c8c3SGatien Chevallier {
1146*bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1147*bd03c8c3SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1148*bd03c8c3SGatien Chevallier 
1149*bd03c8c3SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1150*bd03c8c3SGatien Chevallier 		if (bank->ready)
1151*bd03c8c3SGatien Chevallier 			continue;
1152*bd03c8c3SGatien Chevallier 
1153*bd03c8c3SGatien Chevallier 		if (bank->rif_cfg) {
1154*bd03c8c3SGatien Chevallier 			res = apply_rif_config(bank);
1155*bd03c8c3SGatien Chevallier 			if (res) {
1156*bd03c8c3SGatien Chevallier 				EMSG("Failed to set GPIO bank %c RIF config",
1157*bd03c8c3SGatien Chevallier 				     'A' + bank->bank_id);
1158*bd03c8c3SGatien Chevallier 				STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank,
1159*bd03c8c3SGatien Chevallier 					      link);
1160*bd03c8c3SGatien Chevallier 				return res;
1161*bd03c8c3SGatien Chevallier 			}
1162*bd03c8c3SGatien Chevallier 		} else {
1163*bd03c8c3SGatien Chevallier 			stm32_gpio_set_conf_sec(bank);
1164*bd03c8c3SGatien Chevallier 		}
1165*bd03c8c3SGatien Chevallier 
1166*bd03c8c3SGatien Chevallier 		bank->ready = true;
1167*bd03c8c3SGatien Chevallier 	}
1168*bd03c8c3SGatien Chevallier 
1169*bd03c8c3SGatien Chevallier 	return TEE_SUCCESS;
1170*bd03c8c3SGatien Chevallier }
1171*bd03c8c3SGatien Chevallier 
11720e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
11730e0435e2SEtienne Carriere 				      const void *compat_data)
11740e0435e2SEtienne Carriere {
1175b38386fbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1176b38386fbSEtienne Carriere 
11770e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
1178b38386fbSEtienne Carriere 	res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
1179b38386fbSEtienne Carriere 	if (res)
1180b38386fbSEtienne Carriere 		return res;
1181b38386fbSEtienne Carriere 
1182*bd03c8c3SGatien Chevallier 	if (STAILQ_EMPTY(&bank_list))
1183*bd03c8c3SGatien Chevallier 		DMSG("no gpio bank for that driver");
1184*bd03c8c3SGatien Chevallier 	else if (apply_sec_cfg())
1185*bd03c8c3SGatien Chevallier 		panic();
1186*bd03c8c3SGatien Chevallier 
1187b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1188b38386fbSEtienne Carriere 	res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
1189b38386fbSEtienne Carriere 					(void *)compat_data);
1190b38386fbSEtienne Carriere 	if (res)
1191*bd03c8c3SGatien Chevallier 		panic();
1192b38386fbSEtienne Carriere #endif
1193b38386fbSEtienne Carriere 
1194b38386fbSEtienne Carriere 	return TEE_SUCCESS;
11950e0435e2SEtienne Carriere }
11960e0435e2SEtienne Carriere 
11970e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
1198e569f6adSEtienne Carriere 	{
1199e569f6adSEtienne Carriere 		.compatible = "st,stm32mp135-pinctrl",
1200b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1201b4893304SGatien Chevallier 			.secure_control = true,
1202*bd03c8c3SGatien Chevallier 			.secure_extended = false,
1203b4893304SGatien Chevallier 		},
1204e569f6adSEtienne Carriere 	},
1205e569f6adSEtienne Carriere 	{
1206e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-pinctrl",
1207b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1208b4893304SGatien Chevallier 			.secure_control = false,
1209*bd03c8c3SGatien Chevallier 			.secure_extended = false,
1210b4893304SGatien Chevallier 		},
1211e569f6adSEtienne Carriere 	},
1212e569f6adSEtienne Carriere 	{
1213e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-z-pinctrl",
1214b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1215b4893304SGatien Chevallier 			.gpioz = true,
1216b4893304SGatien Chevallier 			.secure_control = true,
1217*bd03c8c3SGatien Chevallier 			.secure_extended = false,
1218*bd03c8c3SGatien Chevallier 		},
1219*bd03c8c3SGatien Chevallier 	},
1220*bd03c8c3SGatien Chevallier 	{
1221*bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-pinctrl",
1222*bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1223*bd03c8c3SGatien Chevallier 			.secure_control = true,
1224*bd03c8c3SGatien Chevallier 			.secure_extended = true,
1225*bd03c8c3SGatien Chevallier 		},
1226*bd03c8c3SGatien Chevallier 	},
1227*bd03c8c3SGatien Chevallier 	{
1228*bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-z-pinctrl",
1229*bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1230*bd03c8c3SGatien Chevallier 			.gpioz = true,
1231*bd03c8c3SGatien Chevallier 			.secure_control = true,
1232*bd03c8c3SGatien Chevallier 			.secure_extended = true,
1233b4893304SGatien Chevallier 		},
1234e569f6adSEtienne Carriere 	},
12350e0435e2SEtienne Carriere 	{ }
12360e0435e2SEtienne Carriere };
12370e0435e2SEtienne Carriere 
12380e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
12390e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
12400e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
12410e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
12420e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
12430e0435e2SEtienne Carriere };
1244