xref: /optee_os/core/drivers/stm32_gpio.c (revision 5f27da6951db07f4f53eb2d39229b50a89dd096b)
14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
24b5e93edSEtienne Carriere /*
3bd03c8c3SGatien 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>
12a650c9cbSEtienne Carriere #include <drivers/firewall.h>
13420a32c5SEtienne Carriere #include <drivers/gpio.h>
14b38386fbSEtienne Carriere #include <drivers/pinctrl.h>
154b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h>
16bd03c8c3SGatien Chevallier #include <drivers/stm32_rif.h>
17a650c9cbSEtienne Carriere #include <dt-bindings/gpio/stm32mp_gpio.h>
18*5f27da69SEtienne Carriere #include <dt-bindings/pinctrl/stm32-pinfunc.h>
194b5e93edSEtienne Carriere #include <io.h>
204b5e93edSEtienne Carriere #include <kernel/dt.h>
2165401337SJens Wiklander #include <kernel/boot.h>
224b5e93edSEtienne Carriere #include <kernel/panic.h>
23bfc43b68SGatien Chevallier #include <kernel/pm.h>
244b5e93edSEtienne Carriere #include <kernel/spinlock.h>
25a2fc83d1SJerome Forissier #include <libfdt.h>
264b5e93edSEtienne Carriere #include <mm/core_memprot.h>
274b5e93edSEtienne Carriere #include <stdbool.h>
2869715ce9SEtienne Carriere #include <stdint.h>
294b5e93edSEtienne Carriere #include <stm32_util.h>
309818a481SEtienne Carriere #include <sys/queue.h>
314b5e93edSEtienne Carriere #include <trace.h>
324b5e93edSEtienne Carriere #include <util.h>
334b5e93edSEtienne Carriere 
341001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO
351001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO
361001585eSEtienne Carriere #endif
371001585eSEtienne Carriere 
384b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
394b5e93edSEtienne Carriere 
405eed568cSGatien Chevallier #define GPIO_MODER_OFFSET	U(0x00)
415eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET	U(0x04)
425eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET	U(0x08)
435eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET	U(0x0c)
445eed568cSGatien Chevallier #define GPIO_IDR_OFFSET		U(0x10)
455eed568cSGatien Chevallier #define GPIO_ODR_OFFSET		U(0x14)
465eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET	U(0x18)
475eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET	U(0x20)
485eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET	U(0x24)
495eed568cSGatien Chevallier #define GPIO_SECR_OFFSET	U(0x30)
50bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET	U(0x34)
51bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET	U(0x38)
52bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x)		(U(0x50) + U(0x8) * (x))
53bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x)		(U(0x54) + U(0x8) * (x))
544b5e93edSEtienne Carriere 
555eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT	U(0x8)
564b5e93edSEtienne Carriere 
57bd03c8c3SGatien Chevallier /*
58bd03c8c3SGatien Chevallier  * CIDCFGR register bitfields
59bd03c8c3SGatien Chevallier  */
60bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK	GENMASK_32(23, 16)
61bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK	GENMASK_32(6, 4)
62bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK	(_CIDCFGR_CFEN | _CIDCFGR_SEMEN |	\
63bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SCID_MASK |		\
64bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SEMWL_MASK)
65bd03c8c3SGatien Chevallier 
66bd03c8c3SGatien Chevallier /*
67bd03c8c3SGatien Chevallier  * PRIVCFGR register bitfields
68bd03c8c3SGatien Chevallier  */
69bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK	GENMASK_32(15, 0)
70bd03c8c3SGatien Chevallier 
71bd03c8c3SGatien Chevallier /*
72bd03c8c3SGatien Chevallier  * SECCFGR register bitfields
73bd03c8c3SGatien Chevallier  */
74bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK	GENMASK_32(15, 0)
75bd03c8c3SGatien Chevallier 
76bd03c8c3SGatien Chevallier /*
77bd03c8c3SGatien Chevallier  * RCFGLOCKR register bitfields
78bd03c8c3SGatien Chevallier  */
79bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK	GENMASK_32(15, 0)
80bd03c8c3SGatien Chevallier 
81bd03c8c3SGatien Chevallier /*
82bd03c8c3SGatien Chevallier  * SEMCR register bitfields
83bd03c8c3SGatien Chevallier  */
84bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M	GENMASK_32(6, 4)
85bd03c8c3SGatien Chevallier 
864b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
874b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
884b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
89729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
904b5e93edSEtienne Carriere 
915eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT	U(12)
924b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
935eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT	U(8)
944b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
954b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
964b5e93edSEtienne Carriere 
979818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0	"GPIOA"
989818a481SEtienne Carriere 
9969715ce9SEtienne Carriere #define GPIO_MODE_INPUT		U(0x0)
10069715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT	U(0x1)
10169715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE	U(0x2)
10269715ce9SEtienne Carriere #define GPIO_MODE_ANALOG	U(0x3)
10369715ce9SEtienne Carriere 
10469715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL	U(0x0)
10569715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN	U(0x1)
10669715ce9SEtienne Carriere 
10769715ce9SEtienne Carriere #define GPIO_OSPEED_LOW		U(0x0)
10869715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM	U(0x1)
10969715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH	U(0x2)
11069715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH	U(0x3)
11169715ce9SEtienne Carriere 
11269715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL	U(0x0)
11369715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP	U(0x1)
11469715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN	U(0x2)
11569715ce9SEtienne Carriere 
11669715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW	U(0x0)
11769715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH	U(0x1)
11869715ce9SEtienne Carriere 
119bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED	U(3)
120bd03c8c3SGatien Chevallier 
12169715ce9SEtienne Carriere /*
12269715ce9SEtienne Carriere  * GPIO configuration description structured as single 16bit word
12369715ce9SEtienne Carriere  * for efficient save/restore when GPIO pin suspends or resumes.
12469715ce9SEtienne Carriere  *
12569715ce9SEtienne Carriere  * @mode: One of GPIO_MODE_*
12669715ce9SEtienne Carriere  * @otype: One of GPIO_OTYPE_*
12769715ce9SEtienne Carriere  * @ospeed: One of GPIO_OSPEED_*
12869715ce9SEtienne Carriere  * @pupd: One of GPIO_PUPD_*
12969715ce9SEtienne Carriere  * @od: One of GPIO_OD_*
13069715ce9SEtienne Carriere  * @af: Alternate function numerical ID between 0 and 15
131*5f27da69SEtienne Carriere  * @nsec: Hint on expected secure state of the pin: 0 if secure, 1 otherwise
13269715ce9SEtienne Carriere  */
13369715ce9SEtienne Carriere struct gpio_cfg {
13469715ce9SEtienne Carriere 	uint16_t mode:		2;
13569715ce9SEtienne Carriere 	uint16_t otype:		1;
13669715ce9SEtienne Carriere 	uint16_t ospeed:	2;
13769715ce9SEtienne Carriere 	uint16_t pupd:		2;
13869715ce9SEtienne Carriere 	uint16_t od:		1;
13969715ce9SEtienne Carriere 	uint16_t af:		4;
140*5f27da69SEtienne Carriere 	uint16_t nsec:		1;
14169715ce9SEtienne Carriere };
14269715ce9SEtienne Carriere 
14369715ce9SEtienne Carriere /*
14469715ce9SEtienne Carriere  * Description of a pin and its muxing
14569715ce9SEtienne Carriere  *
14669715ce9SEtienne Carriere  * @bank: GPIO bank identifier as assigned by the platform
14769715ce9SEtienne Carriere  * @pin: Pin number in the GPIO bank
14869715ce9SEtienne Carriere  * @cfg: Pin configuration
14969715ce9SEtienne Carriere  */
15069715ce9SEtienne Carriere struct stm32_pinctrl {
15169715ce9SEtienne Carriere 	uint8_t bank;
15269715ce9SEtienne Carriere 	uint8_t pin;
15369715ce9SEtienne Carriere 	struct gpio_cfg cfg;
15469715ce9SEtienne Carriere };
15569715ce9SEtienne Carriere 
156b38386fbSEtienne Carriere /*
157b38386fbSEtienne Carriere  * struct stm32_pinctrl_array - Array of pins in a pin control state
158b38386fbSEtienne Carriere  * @count: Number of cells in @pinctrl
159b38386fbSEtienne Carriere  * @pinctrl: Pin control configuration
160b38386fbSEtienne Carriere  */
161b38386fbSEtienne Carriere struct stm32_pinctrl_array {
162b38386fbSEtienne Carriere 	size_t count;
163b38386fbSEtienne Carriere 	struct stm32_pinctrl pinctrl[];
164b38386fbSEtienne Carriere };
165b38386fbSEtienne Carriere 
1669818a481SEtienne Carriere /**
1679818a481SEtienne Carriere  * struct stm32_gpio_bank - GPIO bank instance
1689818a481SEtienne Carriere  *
1699818a481SEtienne Carriere  * @base: base address of the GPIO controller registers.
1709818a481SEtienne Carriere  * @clock: clock identifier.
171420a32c5SEtienne Carriere  * @gpio_chip: GPIO chip reference for that GPIO bank
1729818a481SEtienne Carriere  * @ngpios: number of GPIOs.
1739818a481SEtienne Carriere  * @bank_id: Id of the bank.
1749818a481SEtienne Carriere  * @lock: lock protecting the GPIO bank access.
175bd03c8c3SGatien Chevallier  * @rif_cfg: RIF configuration data
176bd03c8c3SGatien Chevallier  * @seccfgr: non-RIF bank secure configuration data
177bd03c8c3SGatien Chevallier  * @sec_support: True if bank supports pin security protection, else false
178bd03c8c3SGatien Chevallier  * @ready: True if configuration is applied, else false
179bd03c8c3SGatien Chevallier  * @is_tdcid: True if OP-TEE runs as Trusted Domain CID
1809818a481SEtienne Carriere  * @link: Link in bank list
1819818a481SEtienne Carriere  */
1829818a481SEtienne Carriere struct stm32_gpio_bank {
1839818a481SEtienne Carriere 	vaddr_t base;
1849818a481SEtienne Carriere 	struct clk *clock;
185420a32c5SEtienne Carriere 	struct gpio_chip gpio_chip;
1869818a481SEtienne Carriere 	unsigned int ngpios;
1879818a481SEtienne Carriere 	unsigned int bank_id;
1889818a481SEtienne Carriere 	unsigned int lock;
189bd03c8c3SGatien Chevallier 	struct rif_conf_data *rif_cfg;
190bd03c8c3SGatien Chevallier 	uint32_t seccfgr;
191b4893304SGatien Chevallier 	bool sec_support;
192bd03c8c3SGatien Chevallier 	bool ready;
193bd03c8c3SGatien Chevallier 	bool is_tdcid;
1949818a481SEtienne Carriere 	STAILQ_ENTRY(stm32_gpio_bank) link;
1959818a481SEtienne Carriere };
1969818a481SEtienne Carriere 
197bfc43b68SGatien Chevallier /*
198bfc43b68SGatien Chevallier  * struct stm32_gpio_pm_state - Consumed GPIO for PM purpose
199bfc43b68SGatien Chevallier  * @gpio_pinctrl: Reference and configuration state for a consumed GPIO
200bfc43b68SGatien Chevallier  * @level: GPIO level
201bfc43b68SGatien Chevallier  * @link: Link in consumed GPIO list
202bfc43b68SGatien Chevallier  */
203bfc43b68SGatien Chevallier struct stm32_gpio_pm_state {
204bfc43b68SGatien Chevallier 	struct stm32_pinctrl gpio_pinctrl;
205bfc43b68SGatien Chevallier 	uint8_t level;
206bfc43b68SGatien Chevallier 	SLIST_ENTRY(stm32_gpio_pm_state) link;
207bfc43b68SGatien Chevallier };
208bfc43b68SGatien Chevallier 
209b4893304SGatien Chevallier /**
210e569f6adSEtienne Carriere  * Compatibility information of supported banks
211b4893304SGatien Chevallier  *
212b4893304SGatien Chevallier  * @gpioz: True if bank is a GPIOZ bank
213b4893304SGatien Chevallier  * @secure_control: Identify GPIO security bank capability.
214bd03c8c3SGatien Chevallier  * @secure_extended: Identify RIF presence.
215e569f6adSEtienne Carriere  */
216e569f6adSEtienne Carriere struct bank_compat {
217e569f6adSEtienne Carriere 	bool gpioz;
218b4893304SGatien Chevallier 	bool secure_control;
219bd03c8c3SGatien Chevallier 	bool secure_extended;
220e569f6adSEtienne Carriere };
221e569f6adSEtienne Carriere 
2224b5e93edSEtienne Carriere static unsigned int gpio_lock;
2234b5e93edSEtienne Carriere 
2249818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
2259818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
2269818a481SEtienne Carriere 
227bfc43b68SGatien Chevallier static SLIST_HEAD(, stm32_gpio_pm_state) consumed_gpios_head;
228bfc43b68SGatien Chevallier 
229420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
230420a32c5SEtienne Carriere 
231420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
232420a32c5SEtienne Carriere {
233420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
234420a32c5SEtienne Carriere }
235420a32c5SEtienne Carriere 
236420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
237420a32c5SEtienne Carriere 					    unsigned int gpio_pin)
238420a32c5SEtienne Carriere {
239420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
240420a32c5SEtienne Carriere 	enum gpio_level level = GPIO_LEVEL_HIGH;
241420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
242420a32c5SEtienne Carriere 	unsigned int mode = 0;
243420a32c5SEtienne Carriere 
244420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2452fd102ebSEtienne Carriere 
2462fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2472fd102ebSEtienne Carriere 		panic();
248420a32c5SEtienne Carriere 
249420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
250420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
251420a32c5SEtienne Carriere 
252420a32c5SEtienne Carriere 	switch (mode) {
253420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
254420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
255420a32c5SEtienne Carriere 		break;
256420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
257420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
258420a32c5SEtienne Carriere 		break;
259420a32c5SEtienne Carriere 	default:
260420a32c5SEtienne Carriere 		panic();
261420a32c5SEtienne Carriere 	}
262420a32c5SEtienne Carriere 
263420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
264420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
265420a32c5SEtienne Carriere 	else
266420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
267420a32c5SEtienne Carriere 
268420a32c5SEtienne Carriere 	clk_disable(bank->clock);
269420a32c5SEtienne Carriere 
270420a32c5SEtienne Carriere 	return level;
271420a32c5SEtienne Carriere }
272420a32c5SEtienne Carriere 
273420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
274420a32c5SEtienne Carriere 				 enum gpio_level level)
275420a32c5SEtienne Carriere {
276420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
277420a32c5SEtienne Carriere 
278420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2792fd102ebSEtienne Carriere 
2802fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2812fd102ebSEtienne Carriere 		panic();
282420a32c5SEtienne Carriere 
283420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
284420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
285420a32c5SEtienne Carriere 
286420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
287420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
288420a32c5SEtienne Carriere 	else
289420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
290420a32c5SEtienne Carriere 
291420a32c5SEtienne Carriere 	clk_disable(bank->clock);
292420a32c5SEtienne Carriere }
293420a32c5SEtienne Carriere 
294420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
295420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
296420a32c5SEtienne Carriere {
297420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
298420a32c5SEtienne Carriere 	uint32_t mode = 0;
299420a32c5SEtienne Carriere 
300420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
3012fd102ebSEtienne Carriere 
3022fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
3032fd102ebSEtienne Carriere 		panic();
304420a32c5SEtienne Carriere 
305420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
306420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
307420a32c5SEtienne Carriere 
308420a32c5SEtienne Carriere 	clk_disable(bank->clock);
309420a32c5SEtienne Carriere 
310420a32c5SEtienne Carriere 	switch (mode) {
311420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
312420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
313420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
314420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
315420a32c5SEtienne Carriere 	default:
316420a32c5SEtienne Carriere 		panic();
317420a32c5SEtienne Carriere 	}
318420a32c5SEtienne Carriere }
319420a32c5SEtienne Carriere 
320420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
321420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
322420a32c5SEtienne Carriere 				     enum gpio_dir direction)
323420a32c5SEtienne Carriere {
324420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
325420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
326420a32c5SEtienne Carriere 	uint32_t mode = 0;
327420a32c5SEtienne Carriere 
328420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
329420a32c5SEtienne Carriere 
330420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
331420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
332420a32c5SEtienne Carriere 	else
333420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
334420a32c5SEtienne Carriere 
3352fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
3362fd102ebSEtienne Carriere 		panic();
337420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
338420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
339420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
340420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
341420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
342420a32c5SEtienne Carriere 	clk_disable(bank->clock);
343420a32c5SEtienne Carriere }
344420a32c5SEtienne Carriere 
345bfc43b68SGatien Chevallier /* Forward reference to the PM callback handler for consumed GPIOs */
346bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, unsigned int pm_hint,
347bfc43b68SGatien Chevallier 				    const struct pm_callback_handle *pm_hdl);
348bfc43b68SGatien Chevallier 
349430c415aSEtienne Carriere /* Forward reference to RIF semaphore release helper function */
350430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank,
351430c415aSEtienne Carriere 					      unsigned int pin);
352430c415aSEtienne Carriere 
353bfc43b68SGatien Chevallier static void stm32_gpio_put_gpio(struct gpio_chip *chip, struct gpio *gpio)
354420a32c5SEtienne Carriere {
355bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
356bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *tstate = NULL;
357bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *state = NULL;
358bfc43b68SGatien Chevallier 	uint32_t exceptions = 0;
359bfc43b68SGatien Chevallier 
360420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
361bfc43b68SGatien Chevallier 
362bfc43b68SGatien Chevallier 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
363bfc43b68SGatien Chevallier 
364bfc43b68SGatien Chevallier 	SLIST_FOREACH_SAFE(state, &consumed_gpios_head, link, tstate) {
365bfc43b68SGatien Chevallier 		if (state->gpio_pinctrl.bank == bank->bank_id &&
366bfc43b68SGatien Chevallier 		    state->gpio_pinctrl.pin == gpio->pin) {
367bfc43b68SGatien Chevallier 			SLIST_REMOVE(&consumed_gpios_head, state,
368bfc43b68SGatien Chevallier 				     stm32_gpio_pm_state, link);
369bfc43b68SGatien Chevallier 			unregister_pm_driver_cb(consumed_gpios_pm, state);
370430c415aSEtienne Carriere 			release_rif_semaphore_if_acquired(bank, gpio->pin);
371bfc43b68SGatien Chevallier 			free(state);
372420a32c5SEtienne Carriere 			free(gpio);
373bfc43b68SGatien Chevallier 			break;
374bfc43b68SGatien Chevallier 		}
375bfc43b68SGatien Chevallier 	}
376bfc43b68SGatien Chevallier 	assert(state);
377bfc43b68SGatien Chevallier 
378bfc43b68SGatien Chevallier 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
379420a32c5SEtienne Carriere }
380420a32c5SEtienne Carriere 
381420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
382420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
383420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
384420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
385420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
386420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
387420a32c5SEtienne Carriere };
388420a32c5SEtienne Carriere 
389420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
390420a32c5SEtienne Carriere {
391420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
392420a32c5SEtienne Carriere }
393420a32c5SEtienne Carriere 
394077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
3954b5e93edSEtienne Carriere {
396077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
3974b5e93edSEtienne Carriere 
398077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
399077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
400077d486eSEtienne Carriere 			return bank;
401077d486eSEtienne Carriere 
402077d486eSEtienne Carriere 	panic();
403077d486eSEtienne Carriere }
404077d486eSEtienne Carriere 
405430c415aSEtienne Carriere #if defined(CFG_STM32_RIF)
4064675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank, unsigned int pin)
4074675225eSEtienne Carriere {
4084675225eSEtienne Carriere 	bool accessible = false;
4094675225eSEtienne Carriere 	uint32_t cidcfgr = 0;
4104675225eSEtienne Carriere 
4114675225eSEtienne Carriere 	if (!bank->rif_cfg)
4124675225eSEtienne Carriere 		return true;
4134675225eSEtienne Carriere 
4144675225eSEtienne Carriere 	if (clk_enable(bank->clock))
4154675225eSEtienne Carriere 		panic();
4164675225eSEtienne Carriere 
4174675225eSEtienne Carriere 	cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin));
4184675225eSEtienne Carriere 
4194675225eSEtienne Carriere 	if (!(cidcfgr & _CIDCFGR_CFEN)) {
4204675225eSEtienne Carriere 		/* Resource can be accessed when CID filtering is disabled */
4214675225eSEtienne Carriere 		accessible = true;
4224675225eSEtienne Carriere 	} else if (stm32_rif_scid_ok(cidcfgr, GPIO_CIDCFGR_SCID_MASK,
4234675225eSEtienne Carriere 				     RIF_CID1)) {
4244675225eSEtienne Carriere 		/* Resource can be accessed if CID1 is statically allowed */
4254675225eSEtienne Carriere 		accessible = true;
4264675225eSEtienne Carriere 	} else if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) {
4274675225eSEtienne Carriere 		/* CID1 is allowed to request the semaphore */
4284675225eSEtienne Carriere 		accessible = true;
4294675225eSEtienne Carriere 	}
4304675225eSEtienne Carriere 
4314675225eSEtienne Carriere 	clk_disable(bank->clock);
4324675225eSEtienne Carriere 
4334675225eSEtienne Carriere 	return accessible;
4344675225eSEtienne Carriere }
4354675225eSEtienne Carriere 
436430c415aSEtienne Carriere static TEE_Result acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank,
437430c415aSEtienne Carriere 						  unsigned int pin)
438430c415aSEtienne Carriere {
439430c415aSEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
440430c415aSEtienne Carriere 	uint32_t cidcfgr = 0;
441430c415aSEtienne Carriere 
442430c415aSEtienne Carriere 	if (!bank->rif_cfg)
443430c415aSEtienne Carriere 		return TEE_SUCCESS;
444430c415aSEtienne Carriere 
445430c415aSEtienne Carriere 	res = clk_enable(bank->clock);
446430c415aSEtienne Carriere 	if (res)
447430c415aSEtienne Carriere 		return res;
448430c415aSEtienne Carriere 
449430c415aSEtienne Carriere 	cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin));
450430c415aSEtienne Carriere 
451430c415aSEtienne Carriere 	if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
452430c415aSEtienne Carriere 		res = stm32_rif_acquire_semaphore(bank->base + GPIO_SEMCR(pin),
453430c415aSEtienne Carriere 						  GPIO_MAX_CID_SUPPORTED);
454430c415aSEtienne Carriere 
455430c415aSEtienne Carriere 	clk_disable(bank->clock);
456430c415aSEtienne Carriere 
457430c415aSEtienne Carriere 	return res;
458430c415aSEtienne Carriere }
459430c415aSEtienne Carriere 
460430c415aSEtienne Carriere static uint32_t semaphore_current_cid(struct stm32_gpio_bank *bank,
461430c415aSEtienne Carriere 				      unsigned int pin)
462430c415aSEtienne Carriere {
463430c415aSEtienne Carriere 	return (io_read32(bank->base + GPIO_SEMCR(pin)) >>
464430c415aSEtienne Carriere 		_CIDCFGR_SCID_SHIFT) &
465430c415aSEtienne Carriere 		GENMASK_32(GPIO_MAX_CID_SUPPORTED - 1, 0);
466430c415aSEtienne Carriere }
467430c415aSEtienne Carriere 
468430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank,
469430c415aSEtienne Carriere 					      unsigned int pin)
470430c415aSEtienne Carriere {
471430c415aSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
472430c415aSEtienne Carriere 	uint32_t cidcfgr = 0;
473430c415aSEtienne Carriere 
474430c415aSEtienne Carriere 	if (!bank->rif_cfg)
475430c415aSEtienne Carriere 		return;
476430c415aSEtienne Carriere 
477430c415aSEtienne Carriere 	res = clk_enable(bank->clock);
478430c415aSEtienne Carriere 	if (res)
479430c415aSEtienne Carriere 		panic();
480430c415aSEtienne Carriere 
481430c415aSEtienne Carriere 	cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin));
482430c415aSEtienne Carriere 
483430c415aSEtienne Carriere 	if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1) &&
484430c415aSEtienne Carriere 	    semaphore_current_cid(bank, pin) == RIF_CID1) {
485430c415aSEtienne Carriere 		res = stm32_rif_release_semaphore(bank->base + GPIO_SEMCR(pin),
486430c415aSEtienne Carriere 						  GPIO_MAX_CID_SUPPORTED);
487430c415aSEtienne Carriere 		if (res) {
488430c415aSEtienne Carriere 			EMSG("Failed to release GPIO %c%u semaphore",
489430c415aSEtienne Carriere 			     bank->bank_id + 'A', pin);
490430c415aSEtienne Carriere 			panic();
491430c415aSEtienne Carriere 		}
492430c415aSEtienne Carriere 	}
493430c415aSEtienne Carriere 
494430c415aSEtienne Carriere 	clk_disable(bank->clock);
495430c415aSEtienne Carriere }
496430c415aSEtienne Carriere #else
4974675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank __unused,
4984675225eSEtienne Carriere 			      unsigned int pin __unused)
4994675225eSEtienne Carriere {
5004675225eSEtienne Carriere 	return true;
5014675225eSEtienne Carriere }
5024675225eSEtienne Carriere 
503430c415aSEtienne Carriere static TEE_Result
504430c415aSEtienne Carriere acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank __unused,
505430c415aSEtienne Carriere 				unsigned int pin __unused)
506430c415aSEtienne Carriere {
507430c415aSEtienne Carriere 	return TEE_SUCCESS;
508430c415aSEtienne Carriere }
509430c415aSEtienne Carriere 
510430c415aSEtienne Carriere static void
511430c415aSEtienne Carriere release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank __unused,
512430c415aSEtienne Carriere 				  unsigned int pin __unused)
513430c415aSEtienne Carriere {
514430c415aSEtienne Carriere }
515430c415aSEtienne Carriere #endif /*CFG_STM32_RIF*/
516430c415aSEtienne Carriere 
5174675225eSEtienne Carriere static bool pin_is_secure(struct stm32_gpio_bank *bank, unsigned int pin)
5184675225eSEtienne Carriere {
5194675225eSEtienne Carriere 	bool secure = false;
5204675225eSEtienne Carriere 
5214675225eSEtienne Carriere 	if (bank->rif_cfg || bank->sec_support) {
5224675225eSEtienne Carriere 		if (clk_enable(bank->clock))
5234675225eSEtienne Carriere 			panic();
5244675225eSEtienne Carriere 
5254675225eSEtienne Carriere 		secure = io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(pin);
5264675225eSEtienne Carriere 
5274675225eSEtienne Carriere 		clk_disable(bank->clock);
5284675225eSEtienne Carriere 	}
5294675225eSEtienne Carriere 
5304675225eSEtienne Carriere 	return secure;
5314675225eSEtienne Carriere }
5324675225eSEtienne Carriere 
533077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
534bfc43b68SGatien Chevallier static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
535077d486eSEtienne Carriere {
536077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
537077d486eSEtienne Carriere 
538077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
539077d486eSEtienne Carriere 		panic();
5404b5e93edSEtienne Carriere 
5414b5e93edSEtienne Carriere 	/*
5424b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
5434b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
5444b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
5454b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
5464b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
5474b5e93edSEtienne Carriere 	 */
548077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
5494b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
5504b5e93edSEtienne Carriere 
551077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
5524b5e93edSEtienne Carriere 
553077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
554077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
5554b5e93edSEtienne Carriere 
556077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
5574b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
5584b5e93edSEtienne Carriere 
559077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
5604b5e93edSEtienne Carriere 
5614b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
562077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
563077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
5644b5e93edSEtienne Carriere 	else
565077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
5664b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
5674b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
5684b5e93edSEtienne Carriere 
569077d486eSEtienne Carriere 	clk_disable(bank->clock);
5704b5e93edSEtienne Carriere }
5714b5e93edSEtienne Carriere 
5724b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
573077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
5744b5e93edSEtienne Carriere {
575077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
57698dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
5774b5e93edSEtienne Carriere 
578077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
579077d486eSEtienne Carriere 		panic();
58098dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
5814b5e93edSEtienne Carriere 
5824b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
583077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
584bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
585bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
5864b5e93edSEtienne Carriere 
5874b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
588077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
589bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
5904b5e93edSEtienne Carriere 
5914b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
592077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
593bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
594bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
5954b5e93edSEtienne Carriere 
5964b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
597077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
598bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
5994b5e93edSEtienne Carriere 
6004b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
6014b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
602077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
603bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
604bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
6054b5e93edSEtienne Carriere 	} else {
6064b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
6074b5e93edSEtienne Carriere 
608077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
609bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
610bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
6114b5e93edSEtienne Carriere 	}
6124b5e93edSEtienne Carriere 
6134b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
614077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
6154b5e93edSEtienne Carriere 
616c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
61798dfcedaSEtienne Carriere 	clk_disable(bank->clock);
6184b5e93edSEtienne Carriere }
6194b5e93edSEtienne Carriere 
6204b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
621b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
622*5f27da69SEtienne Carriere 				int consumer_node __maybe_unused,
6234b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
6244b5e93edSEtienne Carriere {
625*5f27da69SEtienne Carriere 	struct stm32_gpio_bank *bank_ref = NULL;
626b38386fbSEtienne Carriere 	const fdt32_t *cuint = NULL;
627b38386fbSEtienne Carriere 	const fdt32_t *slewrate = NULL;
62810bcbd6cSEtienne Carriere 	int len = 0;
62910bcbd6cSEtienne Carriere 	uint32_t i = 0;
6304b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
6314b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
6324b5e93edSEtienne Carriere 	size_t found = 0;
633*5f27da69SEtienne Carriere 	bool do_panic = false;
6344b5e93edSEtienne Carriere 
6354b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
6364b5e93edSEtienne Carriere 	if (!cuint)
6374b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
6384b5e93edSEtienne Carriere 
6394b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
6404b5e93edSEtienne Carriere 	if (slewrate)
6414b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
6424b5e93edSEtienne Carriere 
6434b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
6444b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
6454b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
6464b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
6474b5e93edSEtienne Carriere 
6484b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
64910bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
65010bcbd6cSEtienne Carriere 		uint32_t bank = 0;
65110bcbd6cSEtienne Carriere 		uint32_t pin = 0;
65210bcbd6cSEtienne Carriere 		uint32_t mode = 0;
6534b5e93edSEtienne Carriere 		uint32_t alternate = 0;
654322cf9e3SEtienne Carriere 		uint32_t odata = 0;
6554b5e93edSEtienne Carriere 		bool opendrain = false;
656*5f27da69SEtienne Carriere 		bool pin_non_secure = true;
6574b5e93edSEtienne Carriere 
6584b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
6594b5e93edSEtienne Carriere 		cuint++;
6604b5e93edSEtienne Carriere 
6614b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
6624b5e93edSEtienne Carriere 
6634b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
6644b5e93edSEtienne Carriere 
6654b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
6664b5e93edSEtienne Carriere 
667*5f27da69SEtienne Carriere 		pin_non_secure = pincfg & STM32_PIN_NSEC;
668*5f27da69SEtienne Carriere 
6694b5e93edSEtienne Carriere 		switch (mode) {
6704b5e93edSEtienne Carriere 		case 0:
6714b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
6724b5e93edSEtienne Carriere 			break;
6734b5e93edSEtienne Carriere 		case 1:
6744b5e93edSEtienne Carriere 		case 2:
6754b5e93edSEtienne Carriere 		case 3:
6764b5e93edSEtienne Carriere 		case 4:
6774b5e93edSEtienne Carriere 		case 5:
6784b5e93edSEtienne Carriere 		case 6:
6794b5e93edSEtienne Carriere 		case 7:
6804b5e93edSEtienne Carriere 		case 8:
6814b5e93edSEtienne Carriere 		case 9:
6824b5e93edSEtienne Carriere 		case 10:
6834b5e93edSEtienne Carriere 		case 11:
6844b5e93edSEtienne Carriere 		case 12:
6854b5e93edSEtienne Carriere 		case 13:
6864b5e93edSEtienne Carriere 		case 14:
6874b5e93edSEtienne Carriere 		case 15:
6884b5e93edSEtienne Carriere 		case 16:
6894b5e93edSEtienne Carriere 			alternate = mode - 1U;
6904b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
6914b5e93edSEtienne Carriere 			break;
6924b5e93edSEtienne Carriere 		case 17:
6934b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
6944b5e93edSEtienne Carriere 			break;
6954b5e93edSEtienne Carriere 		default:
6964b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
6974b5e93edSEtienne Carriere 			break;
6984b5e93edSEtienne Carriere 		}
6994b5e93edSEtienne Carriere 
7004b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
7014b5e93edSEtienne Carriere 			opendrain = true;
7024b5e93edSEtienne Carriere 
703322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-high", NULL) &&
704322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
705322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
706322cf9e3SEtienne Carriere 			odata = 1;
707322cf9e3SEtienne Carriere 		}
708322cf9e3SEtienne Carriere 
709322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-low", NULL) &&
710322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
711322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
712322cf9e3SEtienne Carriere 			odata = 0;
713322cf9e3SEtienne Carriere 		}
714322cf9e3SEtienne Carriere 
7154b5e93edSEtienne Carriere 		if (found < count) {
7164b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
7174b5e93edSEtienne Carriere 
7184b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
7194b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
720b38386fbSEtienne Carriere 			ref->cfg.mode = mode;
721b38386fbSEtienne Carriere 			if (opendrain)
722b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
723b38386fbSEtienne Carriere 			else
724b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
725b38386fbSEtienne Carriere 			ref->cfg.ospeed = speed;
726b38386fbSEtienne Carriere 			ref->cfg.pupd = pull;
727b38386fbSEtienne Carriere 			ref->cfg.od = odata;
728b38386fbSEtienne Carriere 			ref->cfg.af = alternate;
729*5f27da69SEtienne Carriere 			ref->cfg.nsec = pin_non_secure;
730*5f27da69SEtienne Carriere 
731*5f27da69SEtienne Carriere 			bank_ref = stm32_gpio_get_bank(bank);
732*5f27da69SEtienne Carriere 
733*5f27da69SEtienne Carriere 			if (pin >= bank_ref->ngpios) {
734*5f27da69SEtienne Carriere 				EMSG("node %s requests pin %c%u that does not exist",
735*5f27da69SEtienne Carriere 				     fdt_get_name(fdt, consumer_node, NULL),
736*5f27da69SEtienne Carriere 				     bank + 'A', pin);
737*5f27da69SEtienne Carriere 				do_panic = true;
738*5f27da69SEtienne Carriere 			}
7394b5e93edSEtienne Carriere 		}
7404b5e93edSEtienne Carriere 
7414b5e93edSEtienne Carriere 		found++;
7424b5e93edSEtienne Carriere 	}
7434b5e93edSEtienne Carriere 
744*5f27da69SEtienne Carriere 	if (do_panic)
745*5f27da69SEtienne Carriere 		panic();
746*5f27da69SEtienne Carriere 
7474b5e93edSEtienne Carriere 	return (int)found;
7484b5e93edSEtienne Carriere }
7494b5e93edSEtienne Carriere 
750bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op,
751bfc43b68SGatien Chevallier 				    unsigned int pm_hint __unused,
752bfc43b68SGatien Chevallier 				    const struct pm_callback_handle *pm_hdl)
753bfc43b68SGatien Chevallier {
754bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *handle = pm_hdl->handle;
755bfc43b68SGatien Chevallier 	unsigned int bank_id = handle->gpio_pinctrl.bank;
756bfc43b68SGatien Chevallier 	unsigned int pin = handle->gpio_pinctrl.pin;
757bfc43b68SGatien Chevallier 	struct gpio_chip *chip = &stm32_gpio_get_bank(bank_id)->gpio_chip;
758bfc43b68SGatien Chevallier 
759bfc43b68SGatien Chevallier 	if (op == PM_OP_RESUME) {
760bfc43b68SGatien Chevallier 		set_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
761bfc43b68SGatien Chevallier 		if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
762bfc43b68SGatien Chevallier 			stm32_gpio_set_level(chip, pin, handle->level);
763bfc43b68SGatien Chevallier 	} else {
764bfc43b68SGatien Chevallier 		get_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
765bfc43b68SGatien Chevallier 		if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
766bfc43b68SGatien Chevallier 			handle->level = stm32_gpio_get_level(chip, pin);
767bfc43b68SGatien Chevallier 	}
768bfc43b68SGatien Chevallier 
769bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
770bfc43b68SGatien Chevallier }
771bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(consumed_gpios_pm);
772bfc43b68SGatien Chevallier 
773b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
774b357d34fSEtienne Carriere 				    struct gpio **out_gpio)
775420a32c5SEtienne Carriere {
776b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
777430c415aSEtienne Carriere 	const char *consumer_name __maybe_unused = NULL;
7787761b658SEtienne Carriere 	struct stm32_gpio_pm_state *reg_state = NULL;
779bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *state = NULL;
780420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
781420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
782420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
783420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
7844675225eSEtienne Carriere 	bool gpio_secure = true;
785420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
786420a32c5SEtienne Carriere 	uint32_t otype = 0;
787420a32c5SEtienne Carriere 	uint32_t pupd = 0;
788420a32c5SEtienne Carriere 	uint32_t mode = 0;
789420a32c5SEtienne Carriere 
790430c415aSEtienne Carriere 	consumer_name = fdt_get_name(pargs->fdt, pargs->consumer_node,
791430c415aSEtienne Carriere 				     NULL);
792430c415aSEtienne Carriere 
793b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
794b357d34fSEtienne Carriere 	if (res)
795b357d34fSEtienne Carriere 		return res;
796420a32c5SEtienne Carriere 
797420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
798420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
799420a32c5SEtienne Carriere 		free(gpio);
800b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
801420a32c5SEtienne Carriere 	}
802420a32c5SEtienne Carriere 
8034675225eSEtienne Carriere 	if (gpio->dt_flags & GPIO_STM32_NSEC)
8044675225eSEtienne Carriere 		gpio_secure = false;
8054675225eSEtienne Carriere 
806bfc43b68SGatien Chevallier 	state = calloc(1, sizeof(*state));
807bfc43b68SGatien Chevallier 	if (!state) {
808bfc43b68SGatien Chevallier 		free(gpio);
809bfc43b68SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
810bfc43b68SGatien Chevallier 	}
811bfc43b68SGatien Chevallier 
8127761b658SEtienne Carriere 	SLIST_FOREACH(reg_state, &consumed_gpios_head, link) {
8137761b658SEtienne Carriere 		if (reg_state->gpio_pinctrl.bank == bank->bank_id &&
8147761b658SEtienne Carriere 		    reg_state->gpio_pinctrl.pin == gpio->pin) {
8157761b658SEtienne Carriere 			EMSG("node %s: GPIO %c%u is used by another device",
8164675225eSEtienne Carriere 			     consumer_name, bank->bank_id + 'A', gpio->pin);
8177761b658SEtienne Carriere 			free(state);
8187761b658SEtienne Carriere 			free(gpio);
8197761b658SEtienne Carriere 			return TEE_ERROR_GENERIC;
8207761b658SEtienne Carriere 		}
8217761b658SEtienne Carriere 	}
8227761b658SEtienne Carriere 
8234675225eSEtienne Carriere 	if (!pin_is_accessible(bank, gpio->pin)) {
8244675225eSEtienne Carriere 		EMSG("node %s requests pin on GPIO %c%u which access is denied",
8254675225eSEtienne Carriere 		     consumer_name, bank->bank_id + 'A', gpio->pin);
8264675225eSEtienne Carriere 		panic();
8274675225eSEtienne Carriere 	}
8284675225eSEtienne Carriere 
829430c415aSEtienne Carriere 	res = acquire_rif_semaphore_if_needed(bank, gpio->pin);
830430c415aSEtienne Carriere 	if (res) {
831430c415aSEtienne Carriere 		EMSG("Failed to acquire GPIO %c%u semaphore for node %s",
832430c415aSEtienne Carriere 		     bank->bank_id + 'A', gpio->pin, consumer_name);
833430c415aSEtienne Carriere 		return res;
834430c415aSEtienne Carriere 	}
835430c415aSEtienne Carriere 
8364675225eSEtienne Carriere 	if (gpio_secure && !(bank->rif_cfg || bank->sec_support)) {
8374675225eSEtienne Carriere 		EMSG("node %s requests secure GPIO %c%u that cannot be secured",
8384675225eSEtienne Carriere 		     consumer_name, bank->bank_id + 'A', gpio->pin);
8394675225eSEtienne Carriere 		panic();
8404675225eSEtienne Carriere 	}
8414675225eSEtienne Carriere 
8424675225eSEtienne Carriere 	if (gpio_secure != pin_is_secure(bank, gpio->pin)) {
8434675225eSEtienne Carriere 		IMSG("WARNING: node %s requests %s GPIO %c%u but pin is %s. Check st,protreg in GPIO bank node %s",
8444675225eSEtienne Carriere 		     consumer_name, gpio_secure ? "secure" : "non-secure",
8454675225eSEtienne Carriere 		     bank->bank_id + 'A', gpio->pin,
8464675225eSEtienne Carriere 		     pin_is_secure(bank, gpio->pin) ? "secure" : "non-secure",
8474675225eSEtienne Carriere 		     fdt_get_name(pargs->fdt, pargs->phandle_node, NULL));
8484675225eSEtienne Carriere 		if (!IS_ENABLED(CFG_INSECURE))
8494675225eSEtienne Carriere 			panic();
8504675225eSEtienne Carriere 	}
8514675225eSEtienne Carriere 
852bfc43b68SGatien Chevallier 	state->gpio_pinctrl.pin = gpio->pin;
853bfc43b68SGatien Chevallier 	state->gpio_pinctrl.bank = bank->bank_id;
854bfc43b68SGatien Chevallier 	SLIST_INSERT_HEAD(&consumed_gpios_head, state, link);
855bfc43b68SGatien Chevallier 
856bfc43b68SGatien Chevallier 	register_pm_driver_cb(consumed_gpios_pm, state, "stm32-gpio-state");
857bfc43b68SGatien Chevallier 
858420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
859420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
860420a32c5SEtienne Carriere 
861420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
862420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
863420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
864420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
865420a32c5SEtienne Carriere 	else
866420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
867420a32c5SEtienne Carriere 
868420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
869420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
870420a32c5SEtienne Carriere 	else
871420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
872420a32c5SEtienne Carriere 
873420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
874420a32c5SEtienne Carriere 		panic();
875420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
876420a32c5SEtienne Carriere 
877420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
878420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
879420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
880420a32c5SEtienne Carriere 
881420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
882420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
883420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
884420a32c5SEtienne Carriere 
885420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
886420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
887420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
888420a32c5SEtienne Carriere 
889420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
890420a32c5SEtienne Carriere 	clk_disable(bank->clock);
891420a32c5SEtienne Carriere 
892420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
893420a32c5SEtienne Carriere 
894b357d34fSEtienne Carriere 	*out_gpio = gpio;
895420a32c5SEtienne Carriere 
896b357d34fSEtienne Carriere 	return TEE_SUCCESS;
897420a32c5SEtienne Carriere }
898420a32c5SEtienne Carriere 
8999818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
9009818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
9019818a481SEtienne Carriere {
9029818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
9039818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
9049818a481SEtienne Carriere 	int len = 0;
9059818a481SEtienne Carriere 
9069818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
9079818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
9089818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
9099818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
9109818a481SEtienne Carriere 
9119818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
9129818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
9139818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
9149818a481SEtienne Carriere 
9159818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
9169818a481SEtienne Carriere }
9179818a481SEtienne Carriere 
9189818a481SEtienne Carriere /*
9199818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
9209818a481SEtienne Carriere  * registered in the GPIO bank link.
9219818a481SEtienne Carriere  */
9229818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
9239818a481SEtienne Carriere {
9249818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
9259818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
9269818a481SEtienne Carriere 
9279818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
9289818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
9299818a481SEtienne Carriere 			return true;
9309818a481SEtienne Carriere 
9319818a481SEtienne Carriere 	return false;
9329818a481SEtienne Carriere }
9339818a481SEtienne Carriere 
9349def1fb7SGatien Chevallier #ifdef CFG_STM32_RIF
935a72f07daSEtienne Carriere static TEE_Result handle_available_semaphores(struct stm32_gpio_bank *bank,
936a72f07daSEtienne Carriere 					      uint32_t gpios_mask)
937bd03c8c3SGatien Chevallier {
938bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
939bd03c8c3SGatien Chevallier 	uint32_t cidcfgr = 0;
940bd03c8c3SGatien Chevallier 	unsigned int i = 0;
941bd03c8c3SGatien Chevallier 
9429def1fb7SGatien Chevallier 	for (i = 0 ; i < bank->ngpios; i++) {
943a72f07daSEtienne Carriere 		if (!(BIT(i) & gpios_mask))
9449def1fb7SGatien Chevallier 			continue;
9459def1fb7SGatien Chevallier 
9469def1fb7SGatien Chevallier 		cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i));
9479def1fb7SGatien Chevallier 
9489def1fb7SGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
9499def1fb7SGatien Chevallier 			continue;
9509def1fb7SGatien Chevallier 
9519def1fb7SGatien Chevallier 		if (!(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) {
9529def1fb7SGatien Chevallier 			res = stm32_rif_release_semaphore(bank->base +
9539def1fb7SGatien Chevallier 							  GPIO_SEMCR(i),
9549def1fb7SGatien Chevallier 							  MAX_CID_SUPPORTED);
9559def1fb7SGatien Chevallier 			if (res) {
9569def1fb7SGatien Chevallier 				EMSG("Cannot release semaphore for resource %u",
9579def1fb7SGatien Chevallier 				     i);
9589def1fb7SGatien Chevallier 				return res;
9599def1fb7SGatien Chevallier 			}
9609def1fb7SGatien Chevallier 		} else {
9619def1fb7SGatien Chevallier 			res = stm32_rif_acquire_semaphore(bank->base +
9629def1fb7SGatien Chevallier 							  GPIO_SEMCR(i),
9639def1fb7SGatien Chevallier 							  MAX_CID_SUPPORTED);
9649def1fb7SGatien Chevallier 			if (res) {
9659def1fb7SGatien Chevallier 				EMSG("Cannot acquire semaphore for resource %u",
9669def1fb7SGatien Chevallier 				     i);
9679def1fb7SGatien Chevallier 				return res;
9689def1fb7SGatien Chevallier 			}
9699def1fb7SGatien Chevallier 		}
9709def1fb7SGatien Chevallier 	}
9719def1fb7SGatien Chevallier 
9729def1fb7SGatien Chevallier 	return TEE_SUCCESS;
9739def1fb7SGatien Chevallier }
9749def1fb7SGatien Chevallier 
975a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank,
976a72f07daSEtienne Carriere 				   uint32_t gpios_mask)
9779def1fb7SGatien Chevallier {
9789def1fb7SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
9799def1fb7SGatien Chevallier 	unsigned int i = 0;
9809def1fb7SGatien Chevallier 
981bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
982bd03c8c3SGatien Chevallier 		return TEE_SUCCESS;
983bd03c8c3SGatien Chevallier 
984bd03c8c3SGatien Chevallier 	if (clk_enable(bank->clock))
985bd03c8c3SGatien Chevallier 		panic();
986bd03c8c3SGatien Chevallier 
9879def1fb7SGatien Chevallier 	if (bank->is_tdcid) {
988bd03c8c3SGatien Chevallier 		for (i = 0; i < bank->ngpios; i++) {
989a72f07daSEtienne Carriere 			if (!(BIT(i) & gpios_mask))
990bd03c8c3SGatien Chevallier 				continue;
991bd03c8c3SGatien Chevallier 
992bd03c8c3SGatien Chevallier 			/*
9939def1fb7SGatien Chevallier 			 * When TDCID, OP-TEE should be the one to set the CID
9949def1fb7SGatien Chevallier 			 * filtering configuration. Clearing previous
9959def1fb7SGatien Chevallier 			 * configuration prevents undesired events during the
9969def1fb7SGatien Chevallier 			 * only legitimate configuration.
997bd03c8c3SGatien Chevallier 			 */
998bd03c8c3SGatien Chevallier 			io_clrbits32(bank->base + GPIO_CIDCFGR(i),
999bd03c8c3SGatien Chevallier 				     GPIO_CIDCFGR_CONF_MASK);
1000bd03c8c3SGatien Chevallier 		}
10019def1fb7SGatien Chevallier 	} else {
1002a72f07daSEtienne Carriere 		res = handle_available_semaphores(bank, gpios_mask);
10039def1fb7SGatien Chevallier 		if (res)
10049def1fb7SGatien Chevallier 			panic();
1005bd03c8c3SGatien Chevallier 	}
1006bd03c8c3SGatien Chevallier 
1007bd03c8c3SGatien Chevallier 	/* Security and privilege RIF configuration */
1008a72f07daSEtienne Carriere 	io_mask32(bank->base + GPIO_PRIVCFGR_OFFSET,
1009a72f07daSEtienne Carriere 		  bank->rif_cfg->priv_conf[0], gpios_mask);
1010a72f07daSEtienne Carriere 	io_mask32(bank->base + GPIO_SECR_OFFSET,
1011a72f07daSEtienne Carriere 		  bank->rif_cfg->sec_conf[0], gpios_mask);
1012bd03c8c3SGatien Chevallier 
1013bd03c8c3SGatien Chevallier 	if (!bank->is_tdcid) {
1014bd03c8c3SGatien Chevallier 		res = TEE_SUCCESS;
1015bd03c8c3SGatien Chevallier 		goto out;
1016bd03c8c3SGatien Chevallier 	}
1017bd03c8c3SGatien Chevallier 
1018bd03c8c3SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++) {
1019a72f07daSEtienne Carriere 		if (!(BIT(i) & gpios_mask))
1020bd03c8c3SGatien Chevallier 			continue;
1021bd03c8c3SGatien Chevallier 
1022bd03c8c3SGatien Chevallier 		io_clrsetbits32(bank->base + GPIO_CIDCFGR(i),
1023bd03c8c3SGatien Chevallier 				GPIO_CIDCFGR_CONF_MASK,
1024bd03c8c3SGatien Chevallier 				bank->rif_cfg->cid_confs[i]);
1025bd03c8c3SGatien Chevallier 	}
1026bd03c8c3SGatien Chevallier 
1027bd03c8c3SGatien Chevallier 	/*
1028bd03c8c3SGatien Chevallier 	 * Lock RIF configuration if configured. This cannot be undone until
1029bd03c8c3SGatien Chevallier 	 * next reset.
1030bd03c8c3SGatien Chevallier 	 */
1031bd03c8c3SGatien Chevallier 	io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET,
1032bd03c8c3SGatien Chevallier 		     bank->rif_cfg->lock_conf[0]);
1033bd03c8c3SGatien Chevallier 
1034a72f07daSEtienne Carriere 	res = handle_available_semaphores(bank, gpios_mask);
10359def1fb7SGatien Chevallier 	if (res)
10369def1fb7SGatien Chevallier 		panic();
10379def1fb7SGatien Chevallier 
10389def1fb7SGatien Chevallier out:
1039bd03c8c3SGatien Chevallier 	if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) {
1040bd03c8c3SGatien Chevallier 		/* Check that RIF config are applied, panic otherwise */
1041bd03c8c3SGatien Chevallier 		if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) &
1042a72f07daSEtienne Carriere 		     gpios_mask) !=
1043a72f07daSEtienne Carriere 		    (bank->rif_cfg->priv_conf[0] & gpios_mask)) {
1044bd03c8c3SGatien Chevallier 			EMSG("GPIO bank%c priv conf is incorrect",
1045bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
1046bd03c8c3SGatien Chevallier 			panic();
1047bd03c8c3SGatien Chevallier 		}
1048bd03c8c3SGatien Chevallier 
1049a72f07daSEtienne Carriere 		if ((io_read32(bank->base + GPIO_SECR_OFFSET) & gpios_mask) !=
1050a72f07daSEtienne Carriere 		    (bank->rif_cfg->sec_conf[0] & gpios_mask)) {
1051bd03c8c3SGatien Chevallier 			EMSG("GPIO bank %c sec conf is incorrect",
1052bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
1053bd03c8c3SGatien Chevallier 			panic();
1054bd03c8c3SGatien Chevallier 		}
1055bd03c8c3SGatien Chevallier 	}
1056bd03c8c3SGatien Chevallier 
1057bd03c8c3SGatien Chevallier 	clk_disable(bank->clock);
1058bd03c8c3SGatien Chevallier 
1059bd03c8c3SGatien Chevallier 	return res;
1060bd03c8c3SGatien Chevallier }
10619def1fb7SGatien Chevallier #else /* CFG_STM32_RIF */
1062a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank __unused,
1063a72f07daSEtienne Carriere 				   uint32_t gpios_mask __unused)
10649def1fb7SGatien Chevallier {
10659def1fb7SGatien Chevallier 	return TEE_SUCCESS;
10669def1fb7SGatien Chevallier }
10679def1fb7SGatien Chevallier #endif /* CFG_STM32_RIF */
1068bd03c8c3SGatien Chevallier 
1069a650c9cbSEtienne Carriere /* Forward reference to stm32_gpio_set_conf_sec() defined below */
1070a650c9cbSEtienne Carriere static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank);
1071a650c9cbSEtienne Carriere 
1072a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_fw_configure(struct firewall_query *firewall)
1073a650c9cbSEtienne Carriere {
1074a650c9cbSEtienne Carriere 	struct stm32_gpio_bank *bank = firewall->ctrl->priv;
1075a650c9cbSEtienne Carriere 	uint32_t firewall_arg = 0;
1076a650c9cbSEtienne Carriere 	uint32_t gpios_mask = 0;
1077a650c9cbSEtienne Carriere 	bool secure = true;
1078a650c9cbSEtienne Carriere 
1079a650c9cbSEtienne Carriere 	assert(bank->sec_support);
1080a650c9cbSEtienne Carriere 
1081a650c9cbSEtienne Carriere 	if (firewall->arg_count != 1)
1082a650c9cbSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
1083a650c9cbSEtienne Carriere 
1084a650c9cbSEtienne Carriere 	firewall_arg = firewall->args[0];
1085a650c9cbSEtienne Carriere 
1086a650c9cbSEtienne Carriere 	if (bank->rif_cfg) {
1087a650c9cbSEtienne Carriere 		gpios_mask = BIT(RIF_CHANNEL_ID(firewall_arg));
1088a650c9cbSEtienne Carriere 
1089a650c9cbSEtienne Carriere 		/* We're about to change a specific GPIO config */
1090a650c9cbSEtienne Carriere 		bank->rif_cfg->access_mask[0] |= gpios_mask;
1091a650c9cbSEtienne Carriere 
1092a650c9cbSEtienne Carriere 		/*
1093a650c9cbSEtienne Carriere 		 * Update bank RIF config with firewall configuration data
1094a650c9cbSEtienne Carriere 		 * and apply it.
1095a650c9cbSEtienne Carriere 		 */
1096a650c9cbSEtienne Carriere 		stm32_rif_parse_cfg(firewall_arg, bank->rif_cfg,
1097a650c9cbSEtienne Carriere 				    bank->ngpios);
1098a650c9cbSEtienne Carriere 		return apply_rif_config(bank, gpios_mask);
1099a650c9cbSEtienne Carriere 	}
1100a650c9cbSEtienne Carriere 
1101a650c9cbSEtienne Carriere 	/*
1102a650c9cbSEtienne Carriere 	 * Non RIF GPIO banks use a single cell as a bit mask (bits 0 to 15)
1103a650c9cbSEtienne Carriere 	 * to define the a group of GPIO pins (one or several) to configure
1104a650c9cbSEtienne Carriere 	 * for that bank, and GPIO_STM32_NSEC bit flag to set if these pins
1105a650c9cbSEtienne Carriere 	 * are non-secure (flag set) or non-secure (flag cleared).
1106a650c9cbSEtienne Carriere 	 */
1107a650c9cbSEtienne Carriere 	gpios_mask = firewall_arg & GENMASK_32(15, 0);
1108a650c9cbSEtienne Carriere 
1109a650c9cbSEtienne Carriere 	secure = !(firewall_arg & GPIO_STM32_NSEC);
1110a650c9cbSEtienne Carriere 
1111a650c9cbSEtienne Carriere 	if (gpios_mask & ~GENMASK_32(bank->ngpios, 0)) {
1112a650c9cbSEtienne Carriere 		EMSG("Invalid bitmask %#"PRIx32" for GPIO bank %c",
1113a650c9cbSEtienne Carriere 		     gpios_mask, 'A' + bank->bank_id);
1114a650c9cbSEtienne Carriere 		return TEE_ERROR_GENERIC;
1115a650c9cbSEtienne Carriere 	}
1116a650c9cbSEtienne Carriere 
1117a650c9cbSEtienne Carriere 	/* Update bank secure register configuration data and apply it */
1118a650c9cbSEtienne Carriere 	if (secure)
1119a650c9cbSEtienne Carriere 		bank->seccfgr |= gpios_mask;
1120a650c9cbSEtienne Carriere 	else
1121a650c9cbSEtienne Carriere 		bank->seccfgr &= ~gpios_mask;
1122a650c9cbSEtienne Carriere 
1123a650c9cbSEtienne Carriere 	stm32_gpio_set_conf_sec(bank);
1124a650c9cbSEtienne Carriere 
1125a650c9cbSEtienne Carriere 	return TEE_SUCCESS;
1126a650c9cbSEtienne Carriere }
1127a650c9cbSEtienne Carriere 
1128a650c9cbSEtienne Carriere static const struct firewall_controller_ops stm32_gpio_firewall_ops = {
1129a650c9cbSEtienne Carriere 	.set_conf = stm32_gpio_fw_configure,
1130a650c9cbSEtienne Carriere };
1131a650c9cbSEtienne Carriere 
1132bfc43b68SGatien Chevallier static void stm32_gpio_save_rif_config(struct stm32_gpio_bank *bank)
1133bfc43b68SGatien Chevallier {
1134bfc43b68SGatien Chevallier 	size_t i = 0;
1135bfc43b68SGatien Chevallier 
1136bfc43b68SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++)
1137bfc43b68SGatien Chevallier 		bank->rif_cfg->cid_confs[i] = io_read32(bank->base +
1138bfc43b68SGatien Chevallier 							 GPIO_CIDCFGR(i));
1139bfc43b68SGatien Chevallier 
1140bfc43b68SGatien Chevallier 	bank->rif_cfg->priv_conf[0] = io_read32(bank->base +
1141bfc43b68SGatien Chevallier 						GPIO_PRIVCFGR_OFFSET);
1142bfc43b68SGatien Chevallier 	bank->rif_cfg->sec_conf[0] = io_read32(bank->base +
1143bfc43b68SGatien Chevallier 					       GPIO_SECR_OFFSET);
1144bfc43b68SGatien Chevallier 	bank->rif_cfg->lock_conf[0] = io_read32(bank->base +
1145bfc43b68SGatien Chevallier 						GPIO_RCFGLOCKR_OFFSET);
1146bfc43b68SGatien Chevallier }
1147bfc43b68SGatien Chevallier 
1148bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank,
1149bd03c8c3SGatien Chevallier 				      const void *fdt, int node)
1150bd03c8c3SGatien Chevallier {
1151bd03c8c3SGatien Chevallier 	unsigned int i = 0;
1152bd03c8c3SGatien Chevallier 	unsigned int nb_rif_conf = 0;
1153bd03c8c3SGatien Chevallier 	int lenp = 0;
1154bd03c8c3SGatien Chevallier 	const fdt32_t *cuint = NULL;
1155bd03c8c3SGatien Chevallier 
1156bd03c8c3SGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
1157bd03c8c3SGatien Chevallier 	if (!cuint) {
1158bd03c8c3SGatien Chevallier 		DMSG("No RIF configuration available");
1159bd03c8c3SGatien Chevallier 		return;
1160bd03c8c3SGatien Chevallier 	}
1161bd03c8c3SGatien Chevallier 
1162bd03c8c3SGatien Chevallier 	bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg));
1163bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
1164bd03c8c3SGatien Chevallier 		panic();
1165bd03c8c3SGatien Chevallier 
1166bd03c8c3SGatien Chevallier 	bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t));
1167bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->sec_conf)
1168bd03c8c3SGatien Chevallier 		panic();
1169bd03c8c3SGatien Chevallier 
1170bd03c8c3SGatien Chevallier 	nb_rif_conf = (unsigned int)(lenp / sizeof(uint32_t));
1171bd03c8c3SGatien Chevallier 	assert(nb_rif_conf <= bank->ngpios);
1172bd03c8c3SGatien Chevallier 
1173bd03c8c3SGatien Chevallier 	bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t));
1174bd03c8c3SGatien Chevallier 	bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t));
1175bd03c8c3SGatien Chevallier 	bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t));
1176bd03c8c3SGatien Chevallier 	bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t));
1177bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask ||
1178bd03c8c3SGatien Chevallier 	    !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf)
1179bd03c8c3SGatien Chevallier 		panic("Missing memory capacity for GPIOS RIF configuration");
1180bd03c8c3SGatien Chevallier 
1181bd03c8c3SGatien Chevallier 	for (i = 0; i < nb_rif_conf; i++)
1182bd03c8c3SGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg,
1183646ad62bSGatien Chevallier 				    bank->ngpios);
1184bd03c8c3SGatien Chevallier }
1185bd03c8c3SGatien Chevallier 
11869818a481SEtienne Carriere /* Get GPIO bank information from the DT */
11879818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
1188e569f6adSEtienne Carriere 				     const void *compat_data,
11899818a481SEtienne Carriere 				     int range_offset,
11909818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
11919818a481SEtienne Carriere {
1192e569f6adSEtienne Carriere 	const struct bank_compat *compat = compat_data;
11939818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
11949818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
11959818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
11969818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
11979818a481SEtienne Carriere 	struct clk *clk = NULL;
11989818a481SEtienne Carriere 	size_t blen = 0;
11999818a481SEtienne Carriere 	paddr_t pa = 0;
12009818a481SEtienne Carriere 	int len = 0;
12019818a481SEtienne Carriere 	int i = 0;
12029818a481SEtienne Carriere 
12039818a481SEtienne Carriere 	assert(out_bank);
12049818a481SEtienne Carriere 
12059818a481SEtienne Carriere 	/* Probe deferrable devices first */
12069818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
12079818a481SEtienne Carriere 	if (res)
12089818a481SEtienne Carriere 		return res;
12099818a481SEtienne Carriere 
12109818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
12119818a481SEtienne Carriere 	if (!bank)
12129818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
12139818a481SEtienne Carriere 
1214bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
1215bd03c8c3SGatien Chevallier 		res = stm32_rifsc_check_tdcid(&bank->is_tdcid);
1216bd03c8c3SGatien Chevallier 		if (res) {
1217bd03c8c3SGatien Chevallier 			free(bank);
1218bd03c8c3SGatien Chevallier 			return res;
1219bd03c8c3SGatien Chevallier 		}
1220bd03c8c3SGatien Chevallier 	}
1221bd03c8c3SGatien Chevallier 
12229818a481SEtienne Carriere 	/*
12239818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
12249818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
12259818a481SEtienne Carriere 	 */
12266a0116edSEtienne Carriere 	if (fdt_reg_info(fdt, node, &pa, &blen))
12276a0116edSEtienne Carriere 		panic("missing reg or reg size property");
12289818a481SEtienne Carriere 
12299818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
12309818a481SEtienne Carriere 
12319818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
12329818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
12339818a481SEtienne Carriere 	bank->clock = clk;
1234420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
1235b4893304SGatien Chevallier 	bank->sec_support = compat->secure_control;
12369818a481SEtienne Carriere 
12379818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
12389818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
12399818a481SEtienne Carriere 	len /= sizeof(*cuint);
12409818a481SEtienne Carriere 	if (len % 4)
12419818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
12429818a481SEtienne Carriere 
12439818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
12449818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
12459818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
12469818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
12479818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
12489818a481SEtienne Carriere 		cuint += 4;
12499818a481SEtienne Carriere 	}
12509818a481SEtienne Carriere 
1251bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
1252bd03c8c3SGatien Chevallier 		/* RIF configuration */
1253bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
1254bd03c8c3SGatien Chevallier 
1255bd03c8c3SGatien Chevallier 		stm32_parse_gpio_rif_conf(bank, fdt, node);
1256bd03c8c3SGatien Chevallier 	} else if (bank->sec_support) {
1257bd03c8c3SGatien Chevallier 		/* Secure configuration */
1258bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
1259bd03c8c3SGatien Chevallier 		cuint = fdt_getprop(fdt, node, "st,protreg", NULL);
1260bd03c8c3SGatien Chevallier 		if (cuint)
1261bd03c8c3SGatien Chevallier 			bank->seccfgr = fdt32_to_cpu(*cuint);
1262bd03c8c3SGatien Chevallier 		else
1263bd03c8c3SGatien Chevallier 			DMSG("GPIO bank %c assigned to non-secure",
1264bd03c8c3SGatien Chevallier 			     bank->bank_id + 'A');
1265bd03c8c3SGatien Chevallier 	} else {
1266bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_nsec(&pa_va, blen);
1267bd03c8c3SGatien Chevallier 	}
1268bd03c8c3SGatien Chevallier 
1269e569f6adSEtienne Carriere 	if (compat->gpioz)
1270e569f6adSEtienne Carriere 		stm32mp_register_gpioz_pin_count(bank->ngpios);
1271e569f6adSEtienne Carriere 
12729818a481SEtienne Carriere 	*out_bank = bank;
1273bd03c8c3SGatien Chevallier 
12749818a481SEtienne Carriere 	return TEE_SUCCESS;
12759818a481SEtienne Carriere }
12769818a481SEtienne Carriere 
1277a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_firewall_register(const void *fdt, int node,
1278a650c9cbSEtienne Carriere 					       struct stm32_gpio_bank *bank)
1279a650c9cbSEtienne Carriere {
1280a650c9cbSEtienne Carriere 	struct firewall_controller *controller = NULL;
1281a650c9cbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1282a650c9cbSEtienne Carriere 	char bank_name[] = "gpio-bank-X";
1283a650c9cbSEtienne Carriere 	char *name = NULL;
1284a650c9cbSEtienne Carriere 
1285a650c9cbSEtienne Carriere 	if (!IS_ENABLED(CFG_DRIVERS_FIREWALL) ||
1286a650c9cbSEtienne Carriere 	    !bank->sec_support)
1287a650c9cbSEtienne Carriere 		return TEE_SUCCESS;
1288a650c9cbSEtienne Carriere 
1289a650c9cbSEtienne Carriere 	controller = calloc(1, sizeof(*controller));
1290a650c9cbSEtienne Carriere 	if (!controller)
1291a650c9cbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
1292a650c9cbSEtienne Carriere 
1293a650c9cbSEtienne Carriere 	bank_name[sizeof(bank_name) - 2] = 'A' + bank->bank_id;
1294a650c9cbSEtienne Carriere 	name = strdup(bank_name);
1295a650c9cbSEtienne Carriere 
1296a650c9cbSEtienne Carriere 	controller->name = name;
1297a650c9cbSEtienne Carriere 	controller->priv = bank;
1298a650c9cbSEtienne Carriere 	controller->ops = &stm32_gpio_firewall_ops;
1299a650c9cbSEtienne Carriere 
1300a650c9cbSEtienne Carriere 	if (!controller->name)
1301a650c9cbSEtienne Carriere 		EMSG("Warning: out of memory to store bank name");
1302a650c9cbSEtienne Carriere 
1303a650c9cbSEtienne Carriere 	res = firewall_dt_controller_register(fdt, node, controller);
1304a650c9cbSEtienne Carriere 	if (res) {
1305a650c9cbSEtienne Carriere 		free(name);
1306a650c9cbSEtienne Carriere 		free(controller);
1307a650c9cbSEtienne Carriere 	}
1308a650c9cbSEtienne Carriere 
1309a650c9cbSEtienne Carriere 	return res;
1310a650c9cbSEtienne Carriere }
1311a650c9cbSEtienne Carriere 
1312bd03c8c3SGatien Chevallier /* Parse a pinctrl node to register the GPIO banks it describes */
13130e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
13149818a481SEtienne Carriere 					const void *compat_data)
13159818a481SEtienne Carriere {
13169818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
13179818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
13189818a481SEtienne Carriere 	int range_offs = 0;
13199818a481SEtienne Carriere 	int b_node = 0;
13209818a481SEtienne Carriere 	int len = 0;
13219818a481SEtienne Carriere 
13229818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
13239818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
13249818a481SEtienne Carriere 	if (!cuint)
13259818a481SEtienne Carriere 		panic("missing ranges property");
13269818a481SEtienne Carriere 
13279818a481SEtienne Carriere 	len /= sizeof(*cuint);
13289818a481SEtienne Carriere 	if (len == 3)
13299818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
13309818a481SEtienne Carriere 
13319818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
13329818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
13339818a481SEtienne Carriere 		if (cuint) {
13349818a481SEtienne Carriere 			/*
13359818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
13369818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
13379818a481SEtienne Carriere 			 * bank list.
13389818a481SEtienne Carriere 			 */
13399818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
13409818a481SEtienne Carriere 
13419818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
13429818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
13439818a481SEtienne Carriere 				continue;
13449818a481SEtienne Carriere 
13459818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
13469818a481SEtienne Carriere 						 range_offs, &bank);
13479818a481SEtienne Carriere 			if (res)
13489818a481SEtienne Carriere 				return res;
13499818a481SEtienne Carriere 
1350420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
1351420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
1352420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
1353420a32c5SEtienne Carriere 			if (res)
1354420a32c5SEtienne Carriere 				panic();
1355420a32c5SEtienne Carriere 
1356a650c9cbSEtienne Carriere 			res = stm32_gpio_firewall_register(fdt, b_node, bank);
1357a650c9cbSEtienne Carriere 			if (res)
1358a650c9cbSEtienne Carriere 				panic();
1359a650c9cbSEtienne Carriere 
13609818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
13619818a481SEtienne Carriere 		} else {
13629818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
13639818a481SEtienne Carriere 				panic();
13649818a481SEtienne Carriere 		}
13659818a481SEtienne Carriere 	}
13669818a481SEtienne Carriere 
13679818a481SEtienne Carriere 	return TEE_SUCCESS;
13689818a481SEtienne Carriere }
13699818a481SEtienne Carriere 
1370077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
1371077d486eSEtienne Carriere 			       bool secure)
13724b5e93edSEtienne Carriere {
1373077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
137498dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
13754b5e93edSEtienne Carriere 
1376077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
1377077d486eSEtienne Carriere 		panic();
137898dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
13794b5e93edSEtienne Carriere 
13804b5e93edSEtienne Carriere 	if (secure)
1381077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
13824b5e93edSEtienne Carriere 	else
1383077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
13844b5e93edSEtienne Carriere 
1385c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
138698dfcedaSEtienne Carriere 	clk_disable(bank->clock);
13874b5e93edSEtienne Carriere }
13880e0435e2SEtienne Carriere 
1389b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1390b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
1391b38386fbSEtienne Carriere {
1392b38386fbSEtienne Carriere 	struct stm32_pinctrl_array *ref = conf->priv;
1393b38386fbSEtienne Carriere 	struct stm32_pinctrl *p = ref->pinctrl;
1394430c415aSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
1395430c415aSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1396b38386fbSEtienne Carriere 	size_t pin_count = ref->count;
1397b38386fbSEtienne Carriere 	size_t n = 0;
1398430c415aSEtienne Carriere 	bool error = false;
1399430c415aSEtienne Carriere 
1400430c415aSEtienne Carriere 	for (n = 0; n < pin_count; n++) {
1401430c415aSEtienne Carriere 		bank = stm32_gpio_get_bank(p[n].bank);
1402*5f27da69SEtienne Carriere 
1403*5f27da69SEtienne Carriere 		if (!pin_is_accessible(bank, p[n].pin)) {
1404*5f27da69SEtienne Carriere 			EMSG("Apply pinctrl for pin %c%u that cannot be accessed",
1405*5f27da69SEtienne Carriere 			     p[n].bank + 'A', p[n].pin);
1406*5f27da69SEtienne Carriere 			error = true;
1407*5f27da69SEtienne Carriere 			continue;
1408*5f27da69SEtienne Carriere 		}
1409*5f27da69SEtienne Carriere 
1410430c415aSEtienne Carriere 		res = acquire_rif_semaphore_if_needed(bank, p[n].pin);
1411430c415aSEtienne Carriere 		if (res) {
1412430c415aSEtienne Carriere 			EMSG("Failed to acquire GPIO %c%u semaphore",
1413430c415aSEtienne Carriere 			     bank->bank_id + 'A', p[n].pin);
1414430c415aSEtienne Carriere 			error = true;
1415*5f27da69SEtienne Carriere 			continue;
1416*5f27da69SEtienne Carriere 		}
1417*5f27da69SEtienne Carriere 
1418*5f27da69SEtienne Carriere 		if (p[n].cfg.nsec == !pin_is_secure(bank, p[n].pin))
1419*5f27da69SEtienne Carriere 			continue;
1420*5f27da69SEtienne Carriere 
1421*5f27da69SEtienne Carriere 		if (IS_ENABLED(CFG_INSECURE)) {
1422*5f27da69SEtienne Carriere 			IMSG("WARNING: apply pinctrl for %ssecure pin %c%u that is %ssecure",
1423*5f27da69SEtienne Carriere 			     p[n].cfg.nsec ? "non-" : "",
1424*5f27da69SEtienne Carriere 			     p[n].bank + 'A', p[n].pin,
1425*5f27da69SEtienne Carriere 			     pin_is_secure(bank, p[n].pin) ? "" : "non-");
1426*5f27da69SEtienne Carriere 		} else {
1427*5f27da69SEtienne Carriere 			EMSG("Apply pinctrl for %ssecure pin %c%u that is %ssecure",
1428*5f27da69SEtienne Carriere 			     p[n].cfg.nsec ? "non-" : "",
1429*5f27da69SEtienne Carriere 			     p[n].bank + 'A', p[n].pin,
1430*5f27da69SEtienne Carriere 			     pin_is_secure(bank, p[n].pin) ? "" : "non-");
1431*5f27da69SEtienne Carriere 			error = true;
1432430c415aSEtienne Carriere 		}
1433430c415aSEtienne Carriere 	}
1434430c415aSEtienne Carriere 
1435430c415aSEtienne Carriere 	if (error) {
1436430c415aSEtienne Carriere 		for (n = 0; n < pin_count; n++) {
1437430c415aSEtienne Carriere 			bank = stm32_gpio_get_bank(p[n].bank);
1438430c415aSEtienne Carriere 			release_rif_semaphore_if_acquired(bank, p[n].pin);
1439430c415aSEtienne Carriere 		}
1440430c415aSEtienne Carriere 
1441430c415aSEtienne Carriere 		return TEE_ERROR_SECURITY;
1442430c415aSEtienne Carriere 	}
1443b38386fbSEtienne Carriere 
1444b38386fbSEtienne Carriere 	for (n = 0; n < pin_count; n++)
1445b38386fbSEtienne Carriere 		set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
1446b38386fbSEtienne Carriere 
1447b38386fbSEtienne Carriere 	return TEE_SUCCESS;
1448b38386fbSEtienne Carriere }
1449b38386fbSEtienne Carriere 
1450b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
1451b38386fbSEtienne Carriere {
1452b38386fbSEtienne Carriere 	free(conf);
1453b38386fbSEtienne Carriere }
1454b38386fbSEtienne Carriere 
1455b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
1456b38386fbSEtienne Carriere 	.conf_apply = stm32_pinctrl_conf_apply,
1457b38386fbSEtienne Carriere 	.conf_free = stm32_pinctrl_conf_free,
1458b38386fbSEtienne Carriere };
1459b38386fbSEtienne Carriere 
1460b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
1461b38386fbSEtienne Carriere 
146270ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
146370ac0db5SEtienne Carriere 				 unsigned int *bank, unsigned int *pin,
146470ac0db5SEtienne Carriere 				 unsigned int *count)
146570ac0db5SEtienne Carriere {
146670ac0db5SEtienne Carriere 	size_t conf_index = 0;
146770ac0db5SEtienne Carriere 	size_t pin_count = 0;
146870ac0db5SEtienne Carriere 	size_t n = 0;
146970ac0db5SEtienne Carriere 
147070ac0db5SEtienne Carriere 	assert(count);
147170ac0db5SEtienne Carriere 	if (!pinctrl)
147270ac0db5SEtienne Carriere 		goto out;
147370ac0db5SEtienne Carriere 
147470ac0db5SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
147570ac0db5SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
147670ac0db5SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
147770ac0db5SEtienne Carriere 
147870ac0db5SEtienne Carriere 		/* Consider only the stm32_gpio pins */
147970ac0db5SEtienne Carriere 		if (pinconf->ops != &stm32_pinctrl_ops)
148070ac0db5SEtienne Carriere 			continue;
148170ac0db5SEtienne Carriere 
148270ac0db5SEtienne Carriere 		if (bank || pin) {
148370ac0db5SEtienne Carriere 			for (n = 0; n < ref->count; n++) {
148470ac0db5SEtienne Carriere 				if (bank && pin_count < *count)
148570ac0db5SEtienne Carriere 					bank[pin_count] = ref->pinctrl[n].bank;
148670ac0db5SEtienne Carriere 				if (pin && pin_count < *count)
148770ac0db5SEtienne Carriere 					pin[pin_count] = ref->pinctrl[n].pin;
148870ac0db5SEtienne Carriere 				pin_count++;
148970ac0db5SEtienne Carriere 			}
149070ac0db5SEtienne Carriere 		} else {
149170ac0db5SEtienne Carriere 			pin_count += ref->count;
149270ac0db5SEtienne Carriere 		}
149370ac0db5SEtienne Carriere 	}
149470ac0db5SEtienne Carriere 
149570ac0db5SEtienne Carriere out:
149670ac0db5SEtienne Carriere 	*count = pin_count;
149770ac0db5SEtienne Carriere }
149870ac0db5SEtienne Carriere 
14997f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure)
15007f823a77SEtienne Carriere {
15017f823a77SEtienne Carriere 	size_t conf_index = 0;
15027f823a77SEtienne Carriere 
15037f823a77SEtienne Carriere 	if (!pinctrl)
15047f823a77SEtienne Carriere 		return;
15057f823a77SEtienne Carriere 
15067f823a77SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
15077f823a77SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
15087f823a77SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
15097f823a77SEtienne Carriere 		struct stm32_pinctrl *pc = NULL;
15107f823a77SEtienne Carriere 		size_t n = 0;
15117f823a77SEtienne Carriere 
15127f823a77SEtienne Carriere 		for (n = 0; n < ref->count; n++) {
15137f823a77SEtienne Carriere 			if (pinconf->ops != &stm32_pinctrl_ops)
15147f823a77SEtienne Carriere 				continue;
15157f823a77SEtienne Carriere 
15167f823a77SEtienne Carriere 			pc = ref->pinctrl + n;
15177f823a77SEtienne Carriere 			stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure);
15187f823a77SEtienne Carriere 		}
15197f823a77SEtienne Carriere 	}
15207f823a77SEtienne Carriere }
15217f823a77SEtienne Carriere 
1522b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
1523b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
1524b38386fbSEtienne Carriere 				       void *data __unused,
1525b38386fbSEtienne Carriere 				       struct pinconf **out_pinconf)
1526b38386fbSEtienne Carriere {
1527b38386fbSEtienne Carriere 	struct conf {
1528b38386fbSEtienne Carriere 		struct pinconf pinconf;
1529b38386fbSEtienne Carriere 		struct stm32_pinctrl_array array_ref;
1530b38386fbSEtienne Carriere 	} *loc_conf = NULL;
1531b38386fbSEtienne Carriere 	struct stm32_pinctrl *pinctrl = NULL;
1532b38386fbSEtienne Carriere 	struct pinconf *pinconf = NULL;
1533b38386fbSEtienne Carriere 	const void *fdt = NULL;
1534b38386fbSEtienne Carriere 	size_t pin_count = 0;
1535b38386fbSEtienne Carriere 	int pinctrl_node = 0;
1536b38386fbSEtienne Carriere 	int pinmux_node = 0;
1537b38386fbSEtienne Carriere 	int count = 0;
1538b38386fbSEtienne Carriere 
1539b38386fbSEtienne Carriere 	pinctrl_node = pargs->phandle_node;
1540b38386fbSEtienne Carriere 	fdt = pargs->fdt;
1541b38386fbSEtienne Carriere 	assert(fdt && pinctrl_node);
1542b38386fbSEtienne Carriere 
1543b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1544b38386fbSEtienne Carriere 		if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
1545b38386fbSEtienne Carriere 			pin_count += (size_t)count / sizeof(uint32_t);
1546b38386fbSEtienne Carriere 		else if (count != -FDT_ERR_NOTFOUND)
1547b38386fbSEtienne Carriere 			panic();
1548b38386fbSEtienne Carriere 	}
1549b38386fbSEtienne Carriere 
1550b38386fbSEtienne Carriere 	loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
1551b38386fbSEtienne Carriere 	if (!loc_conf)
1552b38386fbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
1553b38386fbSEtienne Carriere 
1554b38386fbSEtienne Carriere 	pinconf = &loc_conf->pinconf;
1555b38386fbSEtienne Carriere 	pinconf->ops = &stm32_pinctrl_ops;
1556b38386fbSEtienne Carriere 	pinconf->priv = &loc_conf->array_ref;
1557b38386fbSEtienne Carriere 
1558b38386fbSEtienne Carriere 	loc_conf->array_ref.count = pin_count;
1559b38386fbSEtienne Carriere 	pinctrl = loc_conf->array_ref.pinctrl;
1560b38386fbSEtienne Carriere 
1561b38386fbSEtienne Carriere 	count = 0;
1562b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1563b38386fbSEtienne Carriere 		int found = 0;
1564b38386fbSEtienne Carriere 
1565*5f27da69SEtienne Carriere 		found = get_pinctrl_from_fdt(fdt, pinmux_node,
1566*5f27da69SEtienne Carriere 					     pargs->consumer_node,
1567*5f27da69SEtienne Carriere 					     pinctrl + count,
1568b38386fbSEtienne Carriere 					     pin_count - count);
1569b38386fbSEtienne Carriere 		if (found <= 0 && found > ((int)pin_count - count)) {
1570b38386fbSEtienne Carriere 			/* We can't recover from an error here so let's panic */
1571b38386fbSEtienne Carriere 			panic();
1572b38386fbSEtienne Carriere 		}
1573b38386fbSEtienne Carriere 
1574b38386fbSEtienne Carriere 		count += found;
1575b38386fbSEtienne Carriere 	}
1576b38386fbSEtienne Carriere 
1577b38386fbSEtienne Carriere 	*out_pinconf = pinconf;
1578b38386fbSEtienne Carriere 
1579b38386fbSEtienne Carriere 	return TEE_SUCCESS;
1580b38386fbSEtienne Carriere }
1581b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
1582b38386fbSEtienne Carriere 
1583bfc43b68SGatien Chevallier static void stm32_gpio_get_conf_sec(struct stm32_gpio_bank *bank)
1584bfc43b68SGatien Chevallier {
1585bfc43b68SGatien Chevallier 	if (bank->sec_support) {
1586bfc43b68SGatien Chevallier 		clk_enable(bank->clock);
1587bfc43b68SGatien Chevallier 		bank->seccfgr = io_read32(bank->base + GPIO_SECR_OFFSET);
1588bfc43b68SGatien Chevallier 		clk_disable(bank->clock);
1589bfc43b68SGatien Chevallier 	}
1590bfc43b68SGatien Chevallier }
1591bfc43b68SGatien Chevallier 
1592bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank)
1593bd03c8c3SGatien Chevallier {
1594bd03c8c3SGatien Chevallier 	if (bank->sec_support) {
1595bd03c8c3SGatien Chevallier 		clk_enable(bank->clock);
1596bd03c8c3SGatien Chevallier 		io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr);
1597bd03c8c3SGatien Chevallier 		clk_disable(bank->clock);
1598bd03c8c3SGatien Chevallier 	}
1599bd03c8c3SGatien Chevallier }
1600bd03c8c3SGatien Chevallier 
1601bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_resume(void)
1602bfc43b68SGatien Chevallier {
1603bfc43b68SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1604bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1605bfc43b68SGatien Chevallier 
1606bfc43b68SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1607bfc43b68SGatien Chevallier 		if (bank->rif_cfg) {
1608bfc43b68SGatien Chevallier 			if (!bank->is_tdcid)
1609bfc43b68SGatien Chevallier 				continue;
1610bfc43b68SGatien Chevallier 
1611bfc43b68SGatien Chevallier 			bank->rif_cfg->access_mask[0] = GENMASK_32(bank->ngpios,
1612bfc43b68SGatien Chevallier 								   0);
1613bfc43b68SGatien Chevallier 
1614a72f07daSEtienne Carriere 			res = apply_rif_config(bank,
1615a72f07daSEtienne Carriere 					       bank->rif_cfg->access_mask[0]);
1616bfc43b68SGatien Chevallier 			if (res) {
1617bfc43b68SGatien Chevallier 				EMSG("Failed to set GPIO bank %c RIF config",
1618bfc43b68SGatien Chevallier 				     'A' + bank->bank_id);
1619bfc43b68SGatien Chevallier 				return res;
1620bfc43b68SGatien Chevallier 			}
1621bfc43b68SGatien Chevallier 		} else {
1622bfc43b68SGatien Chevallier 			stm32_gpio_set_conf_sec(bank);
1623bfc43b68SGatien Chevallier 		}
1624bfc43b68SGatien Chevallier 	}
1625bfc43b68SGatien Chevallier 
1626bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
1627bfc43b68SGatien Chevallier }
1628bfc43b68SGatien Chevallier 
1629bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_suspend(void)
1630bfc43b68SGatien Chevallier {
1631bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1632bfc43b68SGatien Chevallier 
1633bfc43b68SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1634bfc43b68SGatien Chevallier 		if (bank->rif_cfg) {
1635bfc43b68SGatien Chevallier 			if (bank->is_tdcid)
1636bfc43b68SGatien Chevallier 				stm32_gpio_save_rif_config(bank);
1637bfc43b68SGatien Chevallier 		} else {
1638bfc43b68SGatien Chevallier 			stm32_gpio_get_conf_sec(bank);
1639bfc43b68SGatien Chevallier 		}
1640bfc43b68SGatien Chevallier 	}
1641bfc43b68SGatien Chevallier 
1642bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
1643bfc43b68SGatien Chevallier }
1644bfc43b68SGatien Chevallier 
1645bfc43b68SGatien Chevallier static TEE_Result
1646bfc43b68SGatien Chevallier stm32_gpio_sec_config_pm(enum pm_op op, unsigned int pm_hint,
1647bfc43b68SGatien Chevallier 			 const struct pm_callback_handle *hdl __unused)
1648bfc43b68SGatien Chevallier {
1649bfc43b68SGatien Chevallier 	TEE_Result ret = TEE_ERROR_GENERIC;
1650bfc43b68SGatien Chevallier 
1651bfc43b68SGatien Chevallier 	if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
1652bfc43b68SGatien Chevallier 		return TEE_SUCCESS;
1653bfc43b68SGatien Chevallier 
1654bfc43b68SGatien Chevallier 	if (op == PM_OP_RESUME)
1655bfc43b68SGatien Chevallier 		ret = stm32_gpio_sec_config_resume();
1656bfc43b68SGatien Chevallier 	else
1657bfc43b68SGatien Chevallier 		ret = stm32_gpio_sec_config_suspend();
1658bfc43b68SGatien Chevallier 
1659bfc43b68SGatien Chevallier 	return ret;
1660bfc43b68SGatien Chevallier }
1661bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(stm32_gpio_sec_config_pm);
1662bfc43b68SGatien Chevallier 
1663bd03c8c3SGatien Chevallier /*
1664bd03c8c3SGatien Chevallier  * Several pinctrl nodes can be probed. Their bank will be put in the unique
1665bd03c8c3SGatien Chevallier  * bank_list. To avoid multiple configuration set for a bank when looping
1666bd03c8c3SGatien Chevallier  * over each bank in the bank list, ready is set to true when a bank is
1667bd03c8c3SGatien Chevallier  * configured. Therefore, during other bank probes, the configuration won't
1668bd03c8c3SGatien Chevallier  * be set again.
1669bd03c8c3SGatien Chevallier  */
1670bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void)
1671bd03c8c3SGatien Chevallier {
1672bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1673bd03c8c3SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1674430c415aSEtienne Carriere 	unsigned int pin = 0;
1675bd03c8c3SGatien Chevallier 
1676bd03c8c3SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1677bd03c8c3SGatien Chevallier 		if (bank->ready)
1678bd03c8c3SGatien Chevallier 			continue;
1679bd03c8c3SGatien Chevallier 
1680bd03c8c3SGatien Chevallier 		if (bank->rif_cfg) {
1681a72f07daSEtienne Carriere 			res = apply_rif_config(bank,
1682a72f07daSEtienne Carriere 					       bank->rif_cfg->access_mask[0]);
1683bd03c8c3SGatien Chevallier 			if (res) {
1684bd03c8c3SGatien Chevallier 				EMSG("Failed to set GPIO bank %c RIF config",
1685bd03c8c3SGatien Chevallier 				     'A' + bank->bank_id);
1686bd03c8c3SGatien Chevallier 				STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank,
1687bd03c8c3SGatien Chevallier 					      link);
16889def1fb7SGatien Chevallier 				free(bank);
1689bd03c8c3SGatien Chevallier 				return res;
1690bd03c8c3SGatien Chevallier 			}
1691430c415aSEtienne Carriere 
1692430c415aSEtienne Carriere 			/*
1693430c415aSEtienne Carriere 			 * Semaphores for pinctrl and GPIO are taken when
1694430c415aSEtienne Carriere 			 * these are used (pinctrl state applied, GPIO
1695430c415aSEtienne Carriere 			 * consumed) or when an explicit firewall configuration
1696430c415aSEtienne Carriere 			 * is requested through the firewall framework.
1697430c415aSEtienne Carriere 			 * Therefore release here the taken semaphores.
1698430c415aSEtienne Carriere 			 */
1699430c415aSEtienne Carriere 			for (pin = 0; pin < bank->ngpios; pin++)
1700430c415aSEtienne Carriere 				release_rif_semaphore_if_acquired(bank, pin);
1701430c415aSEtienne Carriere 
1702bd03c8c3SGatien Chevallier 		} else {
1703bd03c8c3SGatien Chevallier 			stm32_gpio_set_conf_sec(bank);
1704bd03c8c3SGatien Chevallier 		}
1705bd03c8c3SGatien Chevallier 
1706bd03c8c3SGatien Chevallier 		bank->ready = true;
1707bd03c8c3SGatien Chevallier 	}
1708bd03c8c3SGatien Chevallier 
1709bd03c8c3SGatien Chevallier 	return TEE_SUCCESS;
1710bd03c8c3SGatien Chevallier }
1711bd03c8c3SGatien Chevallier 
17120e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
17130e0435e2SEtienne Carriere 				      const void *compat_data)
17140e0435e2SEtienne Carriere {
1715bfc43b68SGatien Chevallier 	static bool pm_register;
1716b38386fbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1717b38386fbSEtienne Carriere 
17180e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
1719b38386fbSEtienne Carriere 	res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
1720b38386fbSEtienne Carriere 	if (res)
1721b38386fbSEtienne Carriere 		return res;
1722b38386fbSEtienne Carriere 
1723bd03c8c3SGatien Chevallier 	if (STAILQ_EMPTY(&bank_list))
1724bd03c8c3SGatien Chevallier 		DMSG("no gpio bank for that driver");
1725bd03c8c3SGatien Chevallier 	else if (apply_sec_cfg())
1726bd03c8c3SGatien Chevallier 		panic();
1727bd03c8c3SGatien Chevallier 
1728bfc43b68SGatien Chevallier 	if (!pm_register) {
1729bfc43b68SGatien Chevallier 		/*
1730bfc43b68SGatien Chevallier 		 * Register to PM once for all probed banks to restore
1731bfc43b68SGatien Chevallier 		 * their secure configuration.
1732bfc43b68SGatien Chevallier 		 */
1733bfc43b68SGatien Chevallier 		register_pm_driver_cb(stm32_gpio_sec_config_pm, NULL,
1734bfc43b68SGatien Chevallier 				      "stm32-gpio-secure-config");
1735bfc43b68SGatien Chevallier 		pm_register = true;
1736bfc43b68SGatien Chevallier 	}
1737bfc43b68SGatien Chevallier 
1738b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1739b38386fbSEtienne Carriere 	res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
1740b38386fbSEtienne Carriere 					(void *)compat_data);
1741b38386fbSEtienne Carriere 	if (res)
1742bd03c8c3SGatien Chevallier 		panic();
1743b38386fbSEtienne Carriere #endif
1744b38386fbSEtienne Carriere 
1745b38386fbSEtienne Carriere 	return TEE_SUCCESS;
17460e0435e2SEtienne Carriere }
17470e0435e2SEtienne Carriere 
17480e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
1749e569f6adSEtienne Carriere 	{
1750e569f6adSEtienne Carriere 		.compatible = "st,stm32mp135-pinctrl",
1751b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1752b4893304SGatien Chevallier 			.secure_control = true,
1753bd03c8c3SGatien Chevallier 			.secure_extended = false,
1754b4893304SGatien Chevallier 		},
1755e569f6adSEtienne Carriere 	},
1756e569f6adSEtienne Carriere 	{
1757e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-pinctrl",
1758b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1759b4893304SGatien Chevallier 			.secure_control = false,
1760bd03c8c3SGatien Chevallier 			.secure_extended = false,
1761b4893304SGatien Chevallier 		},
1762e569f6adSEtienne Carriere 	},
1763e569f6adSEtienne Carriere 	{
1764e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-z-pinctrl",
1765b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1766b4893304SGatien Chevallier 			.gpioz = true,
1767b4893304SGatien Chevallier 			.secure_control = true,
1768bd03c8c3SGatien Chevallier 			.secure_extended = false,
1769bd03c8c3SGatien Chevallier 		},
1770bd03c8c3SGatien Chevallier 	},
1771bd03c8c3SGatien Chevallier 	{
1772bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-pinctrl",
1773bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1774bd03c8c3SGatien Chevallier 			.secure_control = true,
1775bd03c8c3SGatien Chevallier 			.secure_extended = true,
1776bd03c8c3SGatien Chevallier 		},
1777bd03c8c3SGatien Chevallier 	},
1778bd03c8c3SGatien Chevallier 	{
1779bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-z-pinctrl",
1780bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1781bd03c8c3SGatien Chevallier 			.gpioz = true,
1782bd03c8c3SGatien Chevallier 			.secure_control = true,
1783bd03c8c3SGatien Chevallier 			.secure_extended = true,
1784b4893304SGatien Chevallier 		},
1785e569f6adSEtienne Carriere 	},
17860e0435e2SEtienne Carriere 	{ }
17870e0435e2SEtienne Carriere };
17880e0435e2SEtienne Carriere 
17890e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
17900e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
17910e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
17920e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
17930e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
17940e0435e2SEtienne Carriere };
1795