xref: /optee_os/core/drivers/stm32_gpio.c (revision a650c9cbf5fa164bba029f8944724dad401d686f)
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>
12*a650c9cbSEtienne 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>
17*a650c9cbSEtienne Carriere #include <dt-bindings/gpio/stm32mp_gpio.h>
184b5e93edSEtienne Carriere #include <io.h>
194b5e93edSEtienne Carriere #include <kernel/dt.h>
2065401337SJens Wiklander #include <kernel/boot.h>
214b5e93edSEtienne Carriere #include <kernel/panic.h>
22bfc43b68SGatien Chevallier #include <kernel/pm.h>
234b5e93edSEtienne Carriere #include <kernel/spinlock.h>
24a2fc83d1SJerome Forissier #include <libfdt.h>
254b5e93edSEtienne Carriere #include <mm/core_memprot.h>
264b5e93edSEtienne Carriere #include <stdbool.h>
2769715ce9SEtienne Carriere #include <stdint.h>
284b5e93edSEtienne Carriere #include <stm32_util.h>
299818a481SEtienne Carriere #include <sys/queue.h>
304b5e93edSEtienne Carriere #include <trace.h>
314b5e93edSEtienne Carriere #include <util.h>
324b5e93edSEtienne Carriere 
331001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO
341001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO
351001585eSEtienne Carriere #endif
361001585eSEtienne Carriere 
374b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
384b5e93edSEtienne Carriere 
395eed568cSGatien Chevallier #define GPIO_MODER_OFFSET	U(0x00)
405eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET	U(0x04)
415eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET	U(0x08)
425eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET	U(0x0c)
435eed568cSGatien Chevallier #define GPIO_IDR_OFFSET		U(0x10)
445eed568cSGatien Chevallier #define GPIO_ODR_OFFSET		U(0x14)
455eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET	U(0x18)
465eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET	U(0x20)
475eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET	U(0x24)
485eed568cSGatien Chevallier #define GPIO_SECR_OFFSET	U(0x30)
49bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET	U(0x34)
50bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET	U(0x38)
51bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x)		(U(0x50) + U(0x8) * (x))
52bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x)		(U(0x54) + U(0x8) * (x))
534b5e93edSEtienne Carriere 
545eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT	U(0x8)
554b5e93edSEtienne Carriere 
56bd03c8c3SGatien Chevallier /*
57bd03c8c3SGatien Chevallier  * CIDCFGR register bitfields
58bd03c8c3SGatien Chevallier  */
59bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK	GENMASK_32(23, 16)
60bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK	GENMASK_32(6, 4)
61bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK	(_CIDCFGR_CFEN | _CIDCFGR_SEMEN |	\
62bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SCID_MASK |		\
63bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SEMWL_MASK)
64bd03c8c3SGatien Chevallier 
65bd03c8c3SGatien Chevallier /*
66bd03c8c3SGatien Chevallier  * PRIVCFGR register bitfields
67bd03c8c3SGatien Chevallier  */
68bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK	GENMASK_32(15, 0)
69bd03c8c3SGatien Chevallier 
70bd03c8c3SGatien Chevallier /*
71bd03c8c3SGatien Chevallier  * SECCFGR register bitfields
72bd03c8c3SGatien Chevallier  */
73bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK	GENMASK_32(15, 0)
74bd03c8c3SGatien Chevallier 
75bd03c8c3SGatien Chevallier /*
76bd03c8c3SGatien Chevallier  * RCFGLOCKR register bitfields
77bd03c8c3SGatien Chevallier  */
78bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK	GENMASK_32(15, 0)
79bd03c8c3SGatien Chevallier 
80bd03c8c3SGatien Chevallier /*
81bd03c8c3SGatien Chevallier  * SEMCR register bitfields
82bd03c8c3SGatien Chevallier  */
83bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M	GENMASK_32(6, 4)
84bd03c8c3SGatien Chevallier 
854b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
864b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
874b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
88729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
894b5e93edSEtienne Carriere 
905eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT	U(12)
914b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
925eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT	U(8)
934b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
944b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
954b5e93edSEtienne Carriere 
969818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0	"GPIOA"
979818a481SEtienne Carriere 
9869715ce9SEtienne Carriere #define GPIO_MODE_INPUT		U(0x0)
9969715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT	U(0x1)
10069715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE	U(0x2)
10169715ce9SEtienne Carriere #define GPIO_MODE_ANALOG	U(0x3)
10269715ce9SEtienne Carriere 
10369715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL	U(0x0)
10469715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN	U(0x1)
10569715ce9SEtienne Carriere 
10669715ce9SEtienne Carriere #define GPIO_OSPEED_LOW		U(0x0)
10769715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM	U(0x1)
10869715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH	U(0x2)
10969715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH	U(0x3)
11069715ce9SEtienne Carriere 
11169715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL	U(0x0)
11269715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP	U(0x1)
11369715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN	U(0x2)
11469715ce9SEtienne Carriere 
11569715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW	U(0x0)
11669715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH	U(0x1)
11769715ce9SEtienne Carriere 
118bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED	U(3)
119bd03c8c3SGatien Chevallier 
12069715ce9SEtienne Carriere /*
12169715ce9SEtienne Carriere  * GPIO configuration description structured as single 16bit word
12269715ce9SEtienne Carriere  * for efficient save/restore when GPIO pin suspends or resumes.
12369715ce9SEtienne Carriere  *
12469715ce9SEtienne Carriere  * @mode: One of GPIO_MODE_*
12569715ce9SEtienne Carriere  * @otype: One of GPIO_OTYPE_*
12669715ce9SEtienne Carriere  * @ospeed: One of GPIO_OSPEED_*
12769715ce9SEtienne Carriere  * @pupd: One of GPIO_PUPD_*
12869715ce9SEtienne Carriere  * @od: One of GPIO_OD_*
12969715ce9SEtienne Carriere  * @af: Alternate function numerical ID between 0 and 15
13069715ce9SEtienne Carriere  */
13169715ce9SEtienne Carriere struct gpio_cfg {
13269715ce9SEtienne Carriere 	uint16_t mode:		2;
13369715ce9SEtienne Carriere 	uint16_t otype:		1;
13469715ce9SEtienne Carriere 	uint16_t ospeed:	2;
13569715ce9SEtienne Carriere 	uint16_t pupd:		2;
13669715ce9SEtienne Carriere 	uint16_t od:		1;
13769715ce9SEtienne Carriere 	uint16_t af:		4;
13869715ce9SEtienne Carriere };
13969715ce9SEtienne Carriere 
14069715ce9SEtienne Carriere /*
14169715ce9SEtienne Carriere  * Description of a pin and its muxing
14269715ce9SEtienne Carriere  *
14369715ce9SEtienne Carriere  * @bank: GPIO bank identifier as assigned by the platform
14469715ce9SEtienne Carriere  * @pin: Pin number in the GPIO bank
14569715ce9SEtienne Carriere  * @cfg: Pin configuration
14669715ce9SEtienne Carriere  */
14769715ce9SEtienne Carriere struct stm32_pinctrl {
14869715ce9SEtienne Carriere 	uint8_t bank;
14969715ce9SEtienne Carriere 	uint8_t pin;
15069715ce9SEtienne Carriere 	struct gpio_cfg cfg;
15169715ce9SEtienne Carriere };
15269715ce9SEtienne Carriere 
153b38386fbSEtienne Carriere /*
154b38386fbSEtienne Carriere  * struct stm32_pinctrl_array - Array of pins in a pin control state
155b38386fbSEtienne Carriere  * @count: Number of cells in @pinctrl
156b38386fbSEtienne Carriere  * @pinctrl: Pin control configuration
157b38386fbSEtienne Carriere  */
158b38386fbSEtienne Carriere struct stm32_pinctrl_array {
159b38386fbSEtienne Carriere 	size_t count;
160b38386fbSEtienne Carriere 	struct stm32_pinctrl pinctrl[];
161b38386fbSEtienne Carriere };
162b38386fbSEtienne Carriere 
1639818a481SEtienne Carriere /**
1649818a481SEtienne Carriere  * struct stm32_gpio_bank - GPIO bank instance
1659818a481SEtienne Carriere  *
1669818a481SEtienne Carriere  * @base: base address of the GPIO controller registers.
1679818a481SEtienne Carriere  * @clock: clock identifier.
168420a32c5SEtienne Carriere  * @gpio_chip: GPIO chip reference for that GPIO bank
1699818a481SEtienne Carriere  * @ngpios: number of GPIOs.
1709818a481SEtienne Carriere  * @bank_id: Id of the bank.
1719818a481SEtienne Carriere  * @lock: lock protecting the GPIO bank access.
172bd03c8c3SGatien Chevallier  * @rif_cfg: RIF configuration data
173bd03c8c3SGatien Chevallier  * @seccfgr: non-RIF bank secure configuration data
174bd03c8c3SGatien Chevallier  * @sec_support: True if bank supports pin security protection, else false
175bd03c8c3SGatien Chevallier  * @ready: True if configuration is applied, else false
176bd03c8c3SGatien Chevallier  * @is_tdcid: True if OP-TEE runs as Trusted Domain CID
1779818a481SEtienne Carriere  * @link: Link in bank list
1789818a481SEtienne Carriere  */
1799818a481SEtienne Carriere struct stm32_gpio_bank {
1809818a481SEtienne Carriere 	vaddr_t base;
1819818a481SEtienne Carriere 	struct clk *clock;
182420a32c5SEtienne Carriere 	struct gpio_chip gpio_chip;
1839818a481SEtienne Carriere 	unsigned int ngpios;
1849818a481SEtienne Carriere 	unsigned int bank_id;
1859818a481SEtienne Carriere 	unsigned int lock;
186bd03c8c3SGatien Chevallier 	struct rif_conf_data *rif_cfg;
187bd03c8c3SGatien Chevallier 	uint32_t seccfgr;
188b4893304SGatien Chevallier 	bool sec_support;
189bd03c8c3SGatien Chevallier 	bool ready;
190bd03c8c3SGatien Chevallier 	bool is_tdcid;
1919818a481SEtienne Carriere 	STAILQ_ENTRY(stm32_gpio_bank) link;
1929818a481SEtienne Carriere };
1939818a481SEtienne Carriere 
194bfc43b68SGatien Chevallier /*
195bfc43b68SGatien Chevallier  * struct stm32_gpio_pm_state - Consumed GPIO for PM purpose
196bfc43b68SGatien Chevallier  * @gpio_pinctrl: Reference and configuration state for a consumed GPIO
197bfc43b68SGatien Chevallier  * @level: GPIO level
198bfc43b68SGatien Chevallier  * @link: Link in consumed GPIO list
199bfc43b68SGatien Chevallier  */
200bfc43b68SGatien Chevallier struct stm32_gpio_pm_state {
201bfc43b68SGatien Chevallier 	struct stm32_pinctrl gpio_pinctrl;
202bfc43b68SGatien Chevallier 	uint8_t level;
203bfc43b68SGatien Chevallier 	SLIST_ENTRY(stm32_gpio_pm_state) link;
204bfc43b68SGatien Chevallier };
205bfc43b68SGatien Chevallier 
206b4893304SGatien Chevallier /**
207e569f6adSEtienne Carriere  * Compatibility information of supported banks
208b4893304SGatien Chevallier  *
209b4893304SGatien Chevallier  * @gpioz: True if bank is a GPIOZ bank
210b4893304SGatien Chevallier  * @secure_control: Identify GPIO security bank capability.
211bd03c8c3SGatien Chevallier  * @secure_extended: Identify RIF presence.
212e569f6adSEtienne Carriere  */
213e569f6adSEtienne Carriere struct bank_compat {
214e569f6adSEtienne Carriere 	bool gpioz;
215b4893304SGatien Chevallier 	bool secure_control;
216bd03c8c3SGatien Chevallier 	bool secure_extended;
217e569f6adSEtienne Carriere };
218e569f6adSEtienne Carriere 
2194b5e93edSEtienne Carriere static unsigned int gpio_lock;
2204b5e93edSEtienne Carriere 
2219818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
2229818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
2239818a481SEtienne Carriere 
224bfc43b68SGatien Chevallier static SLIST_HEAD(, stm32_gpio_pm_state) consumed_gpios_head;
225bfc43b68SGatien Chevallier 
226420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
227420a32c5SEtienne Carriere 
228420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
229420a32c5SEtienne Carriere {
230420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
231420a32c5SEtienne Carriere }
232420a32c5SEtienne Carriere 
233420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
234420a32c5SEtienne Carriere 					    unsigned int gpio_pin)
235420a32c5SEtienne Carriere {
236420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
237420a32c5SEtienne Carriere 	enum gpio_level level = GPIO_LEVEL_HIGH;
238420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
239420a32c5SEtienne Carriere 	unsigned int mode = 0;
240420a32c5SEtienne Carriere 
241420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2422fd102ebSEtienne Carriere 
2432fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2442fd102ebSEtienne Carriere 		panic();
245420a32c5SEtienne Carriere 
246420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
247420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
248420a32c5SEtienne Carriere 
249420a32c5SEtienne Carriere 	switch (mode) {
250420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
251420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
252420a32c5SEtienne Carriere 		break;
253420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
254420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
255420a32c5SEtienne Carriere 		break;
256420a32c5SEtienne Carriere 	default:
257420a32c5SEtienne Carriere 		panic();
258420a32c5SEtienne Carriere 	}
259420a32c5SEtienne Carriere 
260420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
261420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
262420a32c5SEtienne Carriere 	else
263420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
264420a32c5SEtienne Carriere 
265420a32c5SEtienne Carriere 	clk_disable(bank->clock);
266420a32c5SEtienne Carriere 
267420a32c5SEtienne Carriere 	return level;
268420a32c5SEtienne Carriere }
269420a32c5SEtienne Carriere 
270420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
271420a32c5SEtienne Carriere 				 enum gpio_level level)
272420a32c5SEtienne Carriere {
273420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
274420a32c5SEtienne Carriere 
275420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2762fd102ebSEtienne Carriere 
2772fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2782fd102ebSEtienne Carriere 		panic();
279420a32c5SEtienne Carriere 
280420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
281420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
282420a32c5SEtienne Carriere 
283420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
284420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
285420a32c5SEtienne Carriere 	else
286420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
287420a32c5SEtienne Carriere 
288420a32c5SEtienne Carriere 	clk_disable(bank->clock);
289420a32c5SEtienne Carriere }
290420a32c5SEtienne Carriere 
291420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
292420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
293420a32c5SEtienne Carriere {
294420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
295420a32c5SEtienne Carriere 	uint32_t mode = 0;
296420a32c5SEtienne Carriere 
297420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2982fd102ebSEtienne Carriere 
2992fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
3002fd102ebSEtienne Carriere 		panic();
301420a32c5SEtienne Carriere 
302420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
303420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
304420a32c5SEtienne Carriere 
305420a32c5SEtienne Carriere 	clk_disable(bank->clock);
306420a32c5SEtienne Carriere 
307420a32c5SEtienne Carriere 	switch (mode) {
308420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
309420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
310420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
311420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
312420a32c5SEtienne Carriere 	default:
313420a32c5SEtienne Carriere 		panic();
314420a32c5SEtienne Carriere 	}
315420a32c5SEtienne Carriere }
316420a32c5SEtienne Carriere 
317420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
318420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
319420a32c5SEtienne Carriere 				     enum gpio_dir direction)
320420a32c5SEtienne Carriere {
321420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
322420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
323420a32c5SEtienne Carriere 	uint32_t mode = 0;
324420a32c5SEtienne Carriere 
325420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
326420a32c5SEtienne Carriere 
327420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
328420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
329420a32c5SEtienne Carriere 	else
330420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
331420a32c5SEtienne Carriere 
3322fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
3332fd102ebSEtienne Carriere 		panic();
334420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
335420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
336420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
337420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
338420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
339420a32c5SEtienne Carriere 	clk_disable(bank->clock);
340420a32c5SEtienne Carriere }
341420a32c5SEtienne Carriere 
342bfc43b68SGatien Chevallier /* Forward reference to the PM callback handler for consumed GPIOs */
343bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, unsigned int pm_hint,
344bfc43b68SGatien Chevallier 				    const struct pm_callback_handle *pm_hdl);
345bfc43b68SGatien Chevallier 
346bfc43b68SGatien Chevallier static void stm32_gpio_put_gpio(struct gpio_chip *chip, struct gpio *gpio)
347420a32c5SEtienne Carriere {
348bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
349bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *tstate = NULL;
350bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *state = NULL;
351bfc43b68SGatien Chevallier 	uint32_t exceptions = 0;
352bfc43b68SGatien Chevallier 
353420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
354bfc43b68SGatien Chevallier 
355bfc43b68SGatien Chevallier 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
356bfc43b68SGatien Chevallier 
357bfc43b68SGatien Chevallier 	SLIST_FOREACH_SAFE(state, &consumed_gpios_head, link, tstate) {
358bfc43b68SGatien Chevallier 		if (state->gpio_pinctrl.bank == bank->bank_id &&
359bfc43b68SGatien Chevallier 		    state->gpio_pinctrl.pin == gpio->pin) {
360bfc43b68SGatien Chevallier 			SLIST_REMOVE(&consumed_gpios_head, state,
361bfc43b68SGatien Chevallier 				     stm32_gpio_pm_state, link);
362bfc43b68SGatien Chevallier 			unregister_pm_driver_cb(consumed_gpios_pm, state);
363bfc43b68SGatien Chevallier 			free(state);
364420a32c5SEtienne Carriere 			free(gpio);
365bfc43b68SGatien Chevallier 			break;
366bfc43b68SGatien Chevallier 		}
367bfc43b68SGatien Chevallier 	}
368bfc43b68SGatien Chevallier 	assert(state);
369bfc43b68SGatien Chevallier 
370bfc43b68SGatien Chevallier 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
371420a32c5SEtienne Carriere }
372420a32c5SEtienne Carriere 
373420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
374420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
375420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
376420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
377420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
378420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
379420a32c5SEtienne Carriere };
380420a32c5SEtienne Carriere 
381420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
382420a32c5SEtienne Carriere {
383420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
384420a32c5SEtienne Carriere }
385420a32c5SEtienne Carriere 
386077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
3874b5e93edSEtienne Carriere {
388077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
3894b5e93edSEtienne Carriere 
390077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
391077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
392077d486eSEtienne Carriere 			return bank;
393077d486eSEtienne Carriere 
394077d486eSEtienne Carriere 	panic();
395077d486eSEtienne Carriere }
396077d486eSEtienne Carriere 
397077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
398bfc43b68SGatien Chevallier static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
399077d486eSEtienne Carriere {
400077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
401077d486eSEtienne Carriere 
402077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
403077d486eSEtienne Carriere 		panic();
4044b5e93edSEtienne Carriere 
4054b5e93edSEtienne Carriere 	/*
4064b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
4074b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
4084b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
4094b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
4104b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
4114b5e93edSEtienne Carriere 	 */
412077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
4134b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
4144b5e93edSEtienne Carriere 
415077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
4164b5e93edSEtienne Carriere 
417077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
418077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
4194b5e93edSEtienne Carriere 
420077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
4214b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
4224b5e93edSEtienne Carriere 
423077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
4244b5e93edSEtienne Carriere 
4254b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
426077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
427077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
4284b5e93edSEtienne Carriere 	else
429077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
4304b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
4314b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
4324b5e93edSEtienne Carriere 
433077d486eSEtienne Carriere 	clk_disable(bank->clock);
4344b5e93edSEtienne Carriere }
4354b5e93edSEtienne Carriere 
4364b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
437077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
4384b5e93edSEtienne Carriere {
439077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
44098dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
4414b5e93edSEtienne Carriere 
442077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
443077d486eSEtienne Carriere 		panic();
44498dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
4454b5e93edSEtienne Carriere 
4464b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
447077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
448bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
449bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
4504b5e93edSEtienne Carriere 
4514b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
452077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
453bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
4544b5e93edSEtienne Carriere 
4554b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
456077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
457bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
458bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
4594b5e93edSEtienne Carriere 
4604b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
461077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
462bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
4634b5e93edSEtienne Carriere 
4644b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
4654b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
466077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
467bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
468bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
4694b5e93edSEtienne Carriere 	} else {
4704b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
4714b5e93edSEtienne Carriere 
472077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
473bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
474bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
4754b5e93edSEtienne Carriere 	}
4764b5e93edSEtienne Carriere 
4774b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
478077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
4794b5e93edSEtienne Carriere 
480c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
48198dfcedaSEtienne Carriere 	clk_disable(bank->clock);
4824b5e93edSEtienne Carriere }
4834b5e93edSEtienne Carriere 
4844b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
485b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
4864b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
4874b5e93edSEtienne Carriere {
488b38386fbSEtienne Carriere 	const fdt32_t *cuint = NULL;
489b38386fbSEtienne Carriere 	const fdt32_t *slewrate = NULL;
49010bcbd6cSEtienne Carriere 	int len = 0;
49110bcbd6cSEtienne Carriere 	uint32_t i = 0;
4924b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
4934b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
4944b5e93edSEtienne Carriere 	size_t found = 0;
4954b5e93edSEtienne Carriere 
4964b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
4974b5e93edSEtienne Carriere 	if (!cuint)
4984b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
4994b5e93edSEtienne Carriere 
5004b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
5014b5e93edSEtienne Carriere 	if (slewrate)
5024b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
5034b5e93edSEtienne Carriere 
5044b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
5054b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
5064b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
5074b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
5084b5e93edSEtienne Carriere 
5094b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
51010bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
51110bcbd6cSEtienne Carriere 		uint32_t bank = 0;
51210bcbd6cSEtienne Carriere 		uint32_t pin = 0;
51310bcbd6cSEtienne Carriere 		uint32_t mode = 0;
5144b5e93edSEtienne Carriere 		uint32_t alternate = 0;
515322cf9e3SEtienne Carriere 		uint32_t odata = 0;
5164b5e93edSEtienne Carriere 		bool opendrain = false;
5174b5e93edSEtienne Carriere 
5184b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
5194b5e93edSEtienne Carriere 		cuint++;
5204b5e93edSEtienne Carriere 
5214b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
5224b5e93edSEtienne Carriere 
5234b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
5244b5e93edSEtienne Carriere 
5254b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
5264b5e93edSEtienne Carriere 
5274b5e93edSEtienne Carriere 		switch (mode) {
5284b5e93edSEtienne Carriere 		case 0:
5294b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
5304b5e93edSEtienne Carriere 			break;
5314b5e93edSEtienne Carriere 		case 1:
5324b5e93edSEtienne Carriere 		case 2:
5334b5e93edSEtienne Carriere 		case 3:
5344b5e93edSEtienne Carriere 		case 4:
5354b5e93edSEtienne Carriere 		case 5:
5364b5e93edSEtienne Carriere 		case 6:
5374b5e93edSEtienne Carriere 		case 7:
5384b5e93edSEtienne Carriere 		case 8:
5394b5e93edSEtienne Carriere 		case 9:
5404b5e93edSEtienne Carriere 		case 10:
5414b5e93edSEtienne Carriere 		case 11:
5424b5e93edSEtienne Carriere 		case 12:
5434b5e93edSEtienne Carriere 		case 13:
5444b5e93edSEtienne Carriere 		case 14:
5454b5e93edSEtienne Carriere 		case 15:
5464b5e93edSEtienne Carriere 		case 16:
5474b5e93edSEtienne Carriere 			alternate = mode - 1U;
5484b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
5494b5e93edSEtienne Carriere 			break;
5504b5e93edSEtienne Carriere 		case 17:
5514b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
5524b5e93edSEtienne Carriere 			break;
5534b5e93edSEtienne Carriere 		default:
5544b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
5554b5e93edSEtienne Carriere 			break;
5564b5e93edSEtienne Carriere 		}
5574b5e93edSEtienne Carriere 
5584b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
5594b5e93edSEtienne Carriere 			opendrain = true;
5604b5e93edSEtienne Carriere 
561322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-high", NULL) &&
562322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
563322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
564322cf9e3SEtienne Carriere 			odata = 1;
565322cf9e3SEtienne Carriere 		}
566322cf9e3SEtienne Carriere 
567322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-low", NULL) &&
568322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
569322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
570322cf9e3SEtienne Carriere 			odata = 0;
571322cf9e3SEtienne Carriere 		}
572322cf9e3SEtienne Carriere 
5734b5e93edSEtienne Carriere 		if (found < count) {
5744b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
5754b5e93edSEtienne Carriere 
5764b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
5774b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
578b38386fbSEtienne Carriere 			ref->cfg.mode = mode;
579b38386fbSEtienne Carriere 			if (opendrain)
580b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
581b38386fbSEtienne Carriere 			else
582b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
583b38386fbSEtienne Carriere 			ref->cfg.ospeed = speed;
584b38386fbSEtienne Carriere 			ref->cfg.pupd = pull;
585b38386fbSEtienne Carriere 			ref->cfg.od = odata;
586b38386fbSEtienne Carriere 			ref->cfg.af = alternate;
5874b5e93edSEtienne Carriere 		}
5884b5e93edSEtienne Carriere 
5894b5e93edSEtienne Carriere 		found++;
5904b5e93edSEtienne Carriere 	}
5914b5e93edSEtienne Carriere 
5924b5e93edSEtienne Carriere 	return (int)found;
5934b5e93edSEtienne Carriere }
5944b5e93edSEtienne Carriere 
595bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op,
596bfc43b68SGatien Chevallier 				    unsigned int pm_hint __unused,
597bfc43b68SGatien Chevallier 				    const struct pm_callback_handle *pm_hdl)
598bfc43b68SGatien Chevallier {
599bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *handle = pm_hdl->handle;
600bfc43b68SGatien Chevallier 	unsigned int bank_id = handle->gpio_pinctrl.bank;
601bfc43b68SGatien Chevallier 	unsigned int pin = handle->gpio_pinctrl.pin;
602bfc43b68SGatien Chevallier 	struct gpio_chip *chip = &stm32_gpio_get_bank(bank_id)->gpio_chip;
603bfc43b68SGatien Chevallier 
604bfc43b68SGatien Chevallier 	if (op == PM_OP_RESUME) {
605bfc43b68SGatien Chevallier 		set_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
606bfc43b68SGatien Chevallier 		if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
607bfc43b68SGatien Chevallier 			stm32_gpio_set_level(chip, pin, handle->level);
608bfc43b68SGatien Chevallier 	} else {
609bfc43b68SGatien Chevallier 		get_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
610bfc43b68SGatien Chevallier 		if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
611bfc43b68SGatien Chevallier 			handle->level = stm32_gpio_get_level(chip, pin);
612bfc43b68SGatien Chevallier 	}
613bfc43b68SGatien Chevallier 
614bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
615bfc43b68SGatien Chevallier }
616bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(consumed_gpios_pm);
617bfc43b68SGatien Chevallier 
618b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
619b357d34fSEtienne Carriere 				    struct gpio **out_gpio)
620420a32c5SEtienne Carriere {
621b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
6227761b658SEtienne Carriere 	struct stm32_gpio_pm_state *reg_state = NULL;
623bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *state = NULL;
624420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
625420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
626420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
627420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
628420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
629420a32c5SEtienne Carriere 	uint32_t otype = 0;
630420a32c5SEtienne Carriere 	uint32_t pupd = 0;
631420a32c5SEtienne Carriere 	uint32_t mode = 0;
632420a32c5SEtienne Carriere 
633b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
634b357d34fSEtienne Carriere 	if (res)
635b357d34fSEtienne Carriere 		return res;
636420a32c5SEtienne Carriere 
637420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
638420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
639420a32c5SEtienne Carriere 		free(gpio);
640b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
641420a32c5SEtienne Carriere 	}
642420a32c5SEtienne Carriere 
643bfc43b68SGatien Chevallier 	state = calloc(1, sizeof(*state));
644bfc43b68SGatien Chevallier 	if (!state) {
645bfc43b68SGatien Chevallier 		free(gpio);
646bfc43b68SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
647bfc43b68SGatien Chevallier 	}
648bfc43b68SGatien Chevallier 
6497761b658SEtienne Carriere 	SLIST_FOREACH(reg_state, &consumed_gpios_head, link) {
6507761b658SEtienne Carriere 		if (reg_state->gpio_pinctrl.bank == bank->bank_id &&
6517761b658SEtienne Carriere 		    reg_state->gpio_pinctrl.pin == gpio->pin) {
6527761b658SEtienne Carriere 			EMSG("node %s: GPIO %c%u is used by another device",
6537761b658SEtienne Carriere 			     fdt_get_name(pargs->fdt, pargs->consumer_node,
6547761b658SEtienne Carriere 					  NULL),
6557761b658SEtienne Carriere 			     bank->bank_id + 'A', gpio->pin);
6567761b658SEtienne Carriere 			free(state);
6577761b658SEtienne Carriere 			free(gpio);
6587761b658SEtienne Carriere 			return TEE_ERROR_GENERIC;
6597761b658SEtienne Carriere 		}
6607761b658SEtienne Carriere 	}
6617761b658SEtienne Carriere 
662bfc43b68SGatien Chevallier 	state->gpio_pinctrl.pin = gpio->pin;
663bfc43b68SGatien Chevallier 	state->gpio_pinctrl.bank = bank->bank_id;
664bfc43b68SGatien Chevallier 	SLIST_INSERT_HEAD(&consumed_gpios_head, state, link);
665bfc43b68SGatien Chevallier 
666bfc43b68SGatien Chevallier 	register_pm_driver_cb(consumed_gpios_pm, state, "stm32-gpio-state");
667bfc43b68SGatien Chevallier 
668420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
669420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
670420a32c5SEtienne Carriere 
671420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
672420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
673420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
674420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
675420a32c5SEtienne Carriere 	else
676420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
677420a32c5SEtienne Carriere 
678420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
679420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
680420a32c5SEtienne Carriere 	else
681420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
682420a32c5SEtienne Carriere 
683420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
684420a32c5SEtienne Carriere 		panic();
685420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
686420a32c5SEtienne Carriere 
687420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
688420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
689420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
690420a32c5SEtienne Carriere 
691420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
692420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
693420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
694420a32c5SEtienne Carriere 
695420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
696420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
697420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
698420a32c5SEtienne Carriere 
699420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
700420a32c5SEtienne Carriere 	clk_disable(bank->clock);
701420a32c5SEtienne Carriere 
702420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
703420a32c5SEtienne Carriere 
704b357d34fSEtienne Carriere 	*out_gpio = gpio;
705420a32c5SEtienne Carriere 
706b357d34fSEtienne Carriere 	return TEE_SUCCESS;
707420a32c5SEtienne Carriere }
708420a32c5SEtienne Carriere 
7099818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
7109818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
7119818a481SEtienne Carriere {
7129818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
7139818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
7149818a481SEtienne Carriere 	int len = 0;
7159818a481SEtienne Carriere 
7169818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
7179818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
7189818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
7199818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
7209818a481SEtienne Carriere 
7219818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
7229818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
7239818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
7249818a481SEtienne Carriere 
7259818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
7269818a481SEtienne Carriere }
7279818a481SEtienne Carriere 
7289818a481SEtienne Carriere /*
7299818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
7309818a481SEtienne Carriere  * registered in the GPIO bank link.
7319818a481SEtienne Carriere  */
7329818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
7339818a481SEtienne Carriere {
7349818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
7359818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
7369818a481SEtienne Carriere 
7379818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
7389818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
7399818a481SEtienne Carriere 			return true;
7409818a481SEtienne Carriere 
7419818a481SEtienne Carriere 	return false;
7429818a481SEtienne Carriere }
7439818a481SEtienne Carriere 
7449def1fb7SGatien Chevallier #ifdef CFG_STM32_RIF
745a72f07daSEtienne Carriere static TEE_Result handle_available_semaphores(struct stm32_gpio_bank *bank,
746a72f07daSEtienne Carriere 					      uint32_t gpios_mask)
747bd03c8c3SGatien Chevallier {
748bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
749bd03c8c3SGatien Chevallier 	uint32_t cidcfgr = 0;
750bd03c8c3SGatien Chevallier 	unsigned int i = 0;
751bd03c8c3SGatien Chevallier 
7529def1fb7SGatien Chevallier 	for (i = 0 ; i < bank->ngpios; i++) {
753a72f07daSEtienne Carriere 		if (!(BIT(i) & gpios_mask))
7549def1fb7SGatien Chevallier 			continue;
7559def1fb7SGatien Chevallier 
7569def1fb7SGatien Chevallier 		cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i));
7579def1fb7SGatien Chevallier 
7589def1fb7SGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
7599def1fb7SGatien Chevallier 			continue;
7609def1fb7SGatien Chevallier 
7619def1fb7SGatien Chevallier 		if (!(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) {
7629def1fb7SGatien Chevallier 			res = stm32_rif_release_semaphore(bank->base +
7639def1fb7SGatien Chevallier 							  GPIO_SEMCR(i),
7649def1fb7SGatien Chevallier 							  MAX_CID_SUPPORTED);
7659def1fb7SGatien Chevallier 			if (res) {
7669def1fb7SGatien Chevallier 				EMSG("Cannot release semaphore for resource %u",
7679def1fb7SGatien Chevallier 				     i);
7689def1fb7SGatien Chevallier 				return res;
7699def1fb7SGatien Chevallier 			}
7709def1fb7SGatien Chevallier 		} else {
7719def1fb7SGatien Chevallier 			res = stm32_rif_acquire_semaphore(bank->base +
7729def1fb7SGatien Chevallier 							  GPIO_SEMCR(i),
7739def1fb7SGatien Chevallier 							  MAX_CID_SUPPORTED);
7749def1fb7SGatien Chevallier 			if (res) {
7759def1fb7SGatien Chevallier 				EMSG("Cannot acquire semaphore for resource %u",
7769def1fb7SGatien Chevallier 				     i);
7779def1fb7SGatien Chevallier 				return res;
7789def1fb7SGatien Chevallier 			}
7799def1fb7SGatien Chevallier 		}
7809def1fb7SGatien Chevallier 	}
7819def1fb7SGatien Chevallier 
7829def1fb7SGatien Chevallier 	return TEE_SUCCESS;
7839def1fb7SGatien Chevallier }
7849def1fb7SGatien Chevallier 
785a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank,
786a72f07daSEtienne Carriere 				   uint32_t gpios_mask)
7879def1fb7SGatien Chevallier {
7889def1fb7SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
7899def1fb7SGatien Chevallier 	unsigned int i = 0;
7909def1fb7SGatien Chevallier 
791bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
792bd03c8c3SGatien Chevallier 		return TEE_SUCCESS;
793bd03c8c3SGatien Chevallier 
794bd03c8c3SGatien Chevallier 	if (clk_enable(bank->clock))
795bd03c8c3SGatien Chevallier 		panic();
796bd03c8c3SGatien Chevallier 
7979def1fb7SGatien Chevallier 	if (bank->is_tdcid) {
798bd03c8c3SGatien Chevallier 		for (i = 0; i < bank->ngpios; i++) {
799a72f07daSEtienne Carriere 			if (!(BIT(i) & gpios_mask))
800bd03c8c3SGatien Chevallier 				continue;
801bd03c8c3SGatien Chevallier 
802bd03c8c3SGatien Chevallier 			/*
8039def1fb7SGatien Chevallier 			 * When TDCID, OP-TEE should be the one to set the CID
8049def1fb7SGatien Chevallier 			 * filtering configuration. Clearing previous
8059def1fb7SGatien Chevallier 			 * configuration prevents undesired events during the
8069def1fb7SGatien Chevallier 			 * only legitimate configuration.
807bd03c8c3SGatien Chevallier 			 */
808bd03c8c3SGatien Chevallier 			io_clrbits32(bank->base + GPIO_CIDCFGR(i),
809bd03c8c3SGatien Chevallier 				     GPIO_CIDCFGR_CONF_MASK);
810bd03c8c3SGatien Chevallier 		}
8119def1fb7SGatien Chevallier 	} else {
812a72f07daSEtienne Carriere 		res = handle_available_semaphores(bank, gpios_mask);
8139def1fb7SGatien Chevallier 		if (res)
8149def1fb7SGatien Chevallier 			panic();
815bd03c8c3SGatien Chevallier 	}
816bd03c8c3SGatien Chevallier 
817bd03c8c3SGatien Chevallier 	/* Security and privilege RIF configuration */
818a72f07daSEtienne Carriere 	io_mask32(bank->base + GPIO_PRIVCFGR_OFFSET,
819a72f07daSEtienne Carriere 		  bank->rif_cfg->priv_conf[0], gpios_mask);
820a72f07daSEtienne Carriere 	io_mask32(bank->base + GPIO_SECR_OFFSET,
821a72f07daSEtienne Carriere 		  bank->rif_cfg->sec_conf[0], gpios_mask);
822bd03c8c3SGatien Chevallier 
823bd03c8c3SGatien Chevallier 	if (!bank->is_tdcid) {
824bd03c8c3SGatien Chevallier 		res = TEE_SUCCESS;
825bd03c8c3SGatien Chevallier 		goto out;
826bd03c8c3SGatien Chevallier 	}
827bd03c8c3SGatien Chevallier 
828bd03c8c3SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++) {
829a72f07daSEtienne Carriere 		if (!(BIT(i) & gpios_mask))
830bd03c8c3SGatien Chevallier 			continue;
831bd03c8c3SGatien Chevallier 
832bd03c8c3SGatien Chevallier 		io_clrsetbits32(bank->base + GPIO_CIDCFGR(i),
833bd03c8c3SGatien Chevallier 				GPIO_CIDCFGR_CONF_MASK,
834bd03c8c3SGatien Chevallier 				bank->rif_cfg->cid_confs[i]);
835bd03c8c3SGatien Chevallier 	}
836bd03c8c3SGatien Chevallier 
837bd03c8c3SGatien Chevallier 	/*
838bd03c8c3SGatien Chevallier 	 * Lock RIF configuration if configured. This cannot be undone until
839bd03c8c3SGatien Chevallier 	 * next reset.
840bd03c8c3SGatien Chevallier 	 */
841bd03c8c3SGatien Chevallier 	io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET,
842bd03c8c3SGatien Chevallier 		     bank->rif_cfg->lock_conf[0]);
843bd03c8c3SGatien Chevallier 
844a72f07daSEtienne Carriere 	res = handle_available_semaphores(bank, gpios_mask);
8459def1fb7SGatien Chevallier 	if (res)
8469def1fb7SGatien Chevallier 		panic();
8479def1fb7SGatien Chevallier 
8489def1fb7SGatien Chevallier out:
849bd03c8c3SGatien Chevallier 	if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) {
850bd03c8c3SGatien Chevallier 		/* Check that RIF config are applied, panic otherwise */
851bd03c8c3SGatien Chevallier 		if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) &
852a72f07daSEtienne Carriere 		     gpios_mask) !=
853a72f07daSEtienne Carriere 		    (bank->rif_cfg->priv_conf[0] & gpios_mask)) {
854bd03c8c3SGatien Chevallier 			EMSG("GPIO bank%c priv conf is incorrect",
855bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
856bd03c8c3SGatien Chevallier 			panic();
857bd03c8c3SGatien Chevallier 		}
858bd03c8c3SGatien Chevallier 
859a72f07daSEtienne Carriere 		if ((io_read32(bank->base + GPIO_SECR_OFFSET) & gpios_mask) !=
860a72f07daSEtienne Carriere 		    (bank->rif_cfg->sec_conf[0] & gpios_mask)) {
861bd03c8c3SGatien Chevallier 			EMSG("GPIO bank %c sec conf is incorrect",
862bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
863bd03c8c3SGatien Chevallier 			panic();
864bd03c8c3SGatien Chevallier 		}
865bd03c8c3SGatien Chevallier 	}
866bd03c8c3SGatien Chevallier 
867bd03c8c3SGatien Chevallier 	clk_disable(bank->clock);
868bd03c8c3SGatien Chevallier 
869bd03c8c3SGatien Chevallier 	return res;
870bd03c8c3SGatien Chevallier }
8719def1fb7SGatien Chevallier #else /* CFG_STM32_RIF */
872a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank __unused,
873a72f07daSEtienne Carriere 				   uint32_t gpios_mask __unused)
8749def1fb7SGatien Chevallier {
8759def1fb7SGatien Chevallier 	return TEE_SUCCESS;
8769def1fb7SGatien Chevallier }
8779def1fb7SGatien Chevallier #endif /* CFG_STM32_RIF */
878bd03c8c3SGatien Chevallier 
879*a650c9cbSEtienne Carriere /* Forward reference to stm32_gpio_set_conf_sec() defined below */
880*a650c9cbSEtienne Carriere static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank);
881*a650c9cbSEtienne Carriere 
882*a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_fw_configure(struct firewall_query *firewall)
883*a650c9cbSEtienne Carriere {
884*a650c9cbSEtienne Carriere 	struct stm32_gpio_bank *bank = firewall->ctrl->priv;
885*a650c9cbSEtienne Carriere 	uint32_t firewall_arg = 0;
886*a650c9cbSEtienne Carriere 	uint32_t gpios_mask = 0;
887*a650c9cbSEtienne Carriere 	bool secure = true;
888*a650c9cbSEtienne Carriere 
889*a650c9cbSEtienne Carriere 	assert(bank->sec_support);
890*a650c9cbSEtienne Carriere 
891*a650c9cbSEtienne Carriere 	if (firewall->arg_count != 1)
892*a650c9cbSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
893*a650c9cbSEtienne Carriere 
894*a650c9cbSEtienne Carriere 	firewall_arg = firewall->args[0];
895*a650c9cbSEtienne Carriere 
896*a650c9cbSEtienne Carriere 	if (bank->rif_cfg) {
897*a650c9cbSEtienne Carriere 		gpios_mask = BIT(RIF_CHANNEL_ID(firewall_arg));
898*a650c9cbSEtienne Carriere 
899*a650c9cbSEtienne Carriere 		/* We're about to change a specific GPIO config */
900*a650c9cbSEtienne Carriere 		bank->rif_cfg->access_mask[0] |= gpios_mask;
901*a650c9cbSEtienne Carriere 
902*a650c9cbSEtienne Carriere 		/*
903*a650c9cbSEtienne Carriere 		 * Update bank RIF config with firewall configuration data
904*a650c9cbSEtienne Carriere 		 * and apply it.
905*a650c9cbSEtienne Carriere 		 */
906*a650c9cbSEtienne Carriere 		stm32_rif_parse_cfg(firewall_arg, bank->rif_cfg,
907*a650c9cbSEtienne Carriere 				    bank->ngpios);
908*a650c9cbSEtienne Carriere 		return apply_rif_config(bank, gpios_mask);
909*a650c9cbSEtienne Carriere 	}
910*a650c9cbSEtienne Carriere 
911*a650c9cbSEtienne Carriere 	/*
912*a650c9cbSEtienne Carriere 	 * Non RIF GPIO banks use a single cell as a bit mask (bits 0 to 15)
913*a650c9cbSEtienne Carriere 	 * to define the a group of GPIO pins (one or several) to configure
914*a650c9cbSEtienne Carriere 	 * for that bank, and GPIO_STM32_NSEC bit flag to set if these pins
915*a650c9cbSEtienne Carriere 	 * are non-secure (flag set) or non-secure (flag cleared).
916*a650c9cbSEtienne Carriere 	 */
917*a650c9cbSEtienne Carriere 	gpios_mask = firewall_arg & GENMASK_32(15, 0);
918*a650c9cbSEtienne Carriere 
919*a650c9cbSEtienne Carriere 	secure = !(firewall_arg & GPIO_STM32_NSEC);
920*a650c9cbSEtienne Carriere 
921*a650c9cbSEtienne Carriere 	if (gpios_mask & ~GENMASK_32(bank->ngpios, 0)) {
922*a650c9cbSEtienne Carriere 		EMSG("Invalid bitmask %#"PRIx32" for GPIO bank %c",
923*a650c9cbSEtienne Carriere 		     gpios_mask, 'A' + bank->bank_id);
924*a650c9cbSEtienne Carriere 		return TEE_ERROR_GENERIC;
925*a650c9cbSEtienne Carriere 	}
926*a650c9cbSEtienne Carriere 
927*a650c9cbSEtienne Carriere 	/* Update bank secure register configuration data and apply it */
928*a650c9cbSEtienne Carriere 	if (secure)
929*a650c9cbSEtienne Carriere 		bank->seccfgr |= gpios_mask;
930*a650c9cbSEtienne Carriere 	else
931*a650c9cbSEtienne Carriere 		bank->seccfgr &= ~gpios_mask;
932*a650c9cbSEtienne Carriere 
933*a650c9cbSEtienne Carriere 	stm32_gpio_set_conf_sec(bank);
934*a650c9cbSEtienne Carriere 
935*a650c9cbSEtienne Carriere 	return TEE_SUCCESS;
936*a650c9cbSEtienne Carriere }
937*a650c9cbSEtienne Carriere 
938*a650c9cbSEtienne Carriere static const struct firewall_controller_ops stm32_gpio_firewall_ops = {
939*a650c9cbSEtienne Carriere 	.set_conf = stm32_gpio_fw_configure,
940*a650c9cbSEtienne Carriere };
941*a650c9cbSEtienne Carriere 
942bfc43b68SGatien Chevallier static void stm32_gpio_save_rif_config(struct stm32_gpio_bank *bank)
943bfc43b68SGatien Chevallier {
944bfc43b68SGatien Chevallier 	size_t i = 0;
945bfc43b68SGatien Chevallier 
946bfc43b68SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++)
947bfc43b68SGatien Chevallier 		bank->rif_cfg->cid_confs[i] = io_read32(bank->base +
948bfc43b68SGatien Chevallier 							 GPIO_CIDCFGR(i));
949bfc43b68SGatien Chevallier 
950bfc43b68SGatien Chevallier 	bank->rif_cfg->priv_conf[0] = io_read32(bank->base +
951bfc43b68SGatien Chevallier 						GPIO_PRIVCFGR_OFFSET);
952bfc43b68SGatien Chevallier 	bank->rif_cfg->sec_conf[0] = io_read32(bank->base +
953bfc43b68SGatien Chevallier 					       GPIO_SECR_OFFSET);
954bfc43b68SGatien Chevallier 	bank->rif_cfg->lock_conf[0] = io_read32(bank->base +
955bfc43b68SGatien Chevallier 						GPIO_RCFGLOCKR_OFFSET);
956bfc43b68SGatien Chevallier }
957bfc43b68SGatien Chevallier 
958bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank,
959bd03c8c3SGatien Chevallier 				      const void *fdt, int node)
960bd03c8c3SGatien Chevallier {
961bd03c8c3SGatien Chevallier 	unsigned int i = 0;
962bd03c8c3SGatien Chevallier 	unsigned int nb_rif_conf = 0;
963bd03c8c3SGatien Chevallier 	int lenp = 0;
964bd03c8c3SGatien Chevallier 	const fdt32_t *cuint = NULL;
965bd03c8c3SGatien Chevallier 
966bd03c8c3SGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
967bd03c8c3SGatien Chevallier 	if (!cuint) {
968bd03c8c3SGatien Chevallier 		DMSG("No RIF configuration available");
969bd03c8c3SGatien Chevallier 		return;
970bd03c8c3SGatien Chevallier 	}
971bd03c8c3SGatien Chevallier 
972bd03c8c3SGatien Chevallier 	bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg));
973bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
974bd03c8c3SGatien Chevallier 		panic();
975bd03c8c3SGatien Chevallier 
976bd03c8c3SGatien Chevallier 	bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t));
977bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->sec_conf)
978bd03c8c3SGatien Chevallier 		panic();
979bd03c8c3SGatien Chevallier 
980bd03c8c3SGatien Chevallier 	nb_rif_conf = (unsigned int)(lenp / sizeof(uint32_t));
981bd03c8c3SGatien Chevallier 	assert(nb_rif_conf <= bank->ngpios);
982bd03c8c3SGatien Chevallier 
983bd03c8c3SGatien Chevallier 	bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t));
984bd03c8c3SGatien Chevallier 	bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t));
985bd03c8c3SGatien Chevallier 	bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t));
986bd03c8c3SGatien Chevallier 	bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t));
987bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask ||
988bd03c8c3SGatien Chevallier 	    !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf)
989bd03c8c3SGatien Chevallier 		panic("Missing memory capacity for GPIOS RIF configuration");
990bd03c8c3SGatien Chevallier 
991bd03c8c3SGatien Chevallier 	for (i = 0; i < nb_rif_conf; i++)
992bd03c8c3SGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg,
993646ad62bSGatien Chevallier 				    bank->ngpios);
994bd03c8c3SGatien Chevallier }
995bd03c8c3SGatien Chevallier 
9969818a481SEtienne Carriere /* Get GPIO bank information from the DT */
9979818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
998e569f6adSEtienne Carriere 				     const void *compat_data,
9999818a481SEtienne Carriere 				     int range_offset,
10009818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
10019818a481SEtienne Carriere {
1002e569f6adSEtienne Carriere 	const struct bank_compat *compat = compat_data;
10039818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
10049818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
10059818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
10069818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
10079818a481SEtienne Carriere 	struct clk *clk = NULL;
10089818a481SEtienne Carriere 	size_t blen = 0;
10099818a481SEtienne Carriere 	paddr_t pa = 0;
10109818a481SEtienne Carriere 	int len = 0;
10119818a481SEtienne Carriere 	int i = 0;
10129818a481SEtienne Carriere 
10139818a481SEtienne Carriere 	assert(out_bank);
10149818a481SEtienne Carriere 
10159818a481SEtienne Carriere 	/* Probe deferrable devices first */
10169818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
10179818a481SEtienne Carriere 	if (res)
10189818a481SEtienne Carriere 		return res;
10199818a481SEtienne Carriere 
10209818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
10219818a481SEtienne Carriere 	if (!bank)
10229818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
10239818a481SEtienne Carriere 
1024bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
1025bd03c8c3SGatien Chevallier 		res = stm32_rifsc_check_tdcid(&bank->is_tdcid);
1026bd03c8c3SGatien Chevallier 		if (res) {
1027bd03c8c3SGatien Chevallier 			free(bank);
1028bd03c8c3SGatien Chevallier 			return res;
1029bd03c8c3SGatien Chevallier 		}
1030bd03c8c3SGatien Chevallier 	}
1031bd03c8c3SGatien Chevallier 
10329818a481SEtienne Carriere 	/*
10339818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
10349818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
10359818a481SEtienne Carriere 	 */
10366a0116edSEtienne Carriere 	if (fdt_reg_info(fdt, node, &pa, &blen))
10376a0116edSEtienne Carriere 		panic("missing reg or reg size property");
10389818a481SEtienne Carriere 
10399818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
10409818a481SEtienne Carriere 
10419818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
10429818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
10439818a481SEtienne Carriere 	bank->clock = clk;
1044420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
1045b4893304SGatien Chevallier 	bank->sec_support = compat->secure_control;
10469818a481SEtienne Carriere 
10479818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
10489818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
10499818a481SEtienne Carriere 	len /= sizeof(*cuint);
10509818a481SEtienne Carriere 	if (len % 4)
10519818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
10529818a481SEtienne Carriere 
10539818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
10549818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
10559818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
10569818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
10579818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
10589818a481SEtienne Carriere 		cuint += 4;
10599818a481SEtienne Carriere 	}
10609818a481SEtienne Carriere 
1061bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
1062bd03c8c3SGatien Chevallier 		/* RIF configuration */
1063bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
1064bd03c8c3SGatien Chevallier 
1065bd03c8c3SGatien Chevallier 		stm32_parse_gpio_rif_conf(bank, fdt, node);
1066bd03c8c3SGatien Chevallier 	} else if (bank->sec_support) {
1067bd03c8c3SGatien Chevallier 		/* Secure configuration */
1068bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
1069bd03c8c3SGatien Chevallier 		cuint = fdt_getprop(fdt, node, "st,protreg", NULL);
1070bd03c8c3SGatien Chevallier 		if (cuint)
1071bd03c8c3SGatien Chevallier 			bank->seccfgr = fdt32_to_cpu(*cuint);
1072bd03c8c3SGatien Chevallier 		else
1073bd03c8c3SGatien Chevallier 			DMSG("GPIO bank %c assigned to non-secure",
1074bd03c8c3SGatien Chevallier 			     bank->bank_id + 'A');
1075bd03c8c3SGatien Chevallier 	} else {
1076bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_nsec(&pa_va, blen);
1077bd03c8c3SGatien Chevallier 	}
1078bd03c8c3SGatien Chevallier 
1079e569f6adSEtienne Carriere 	if (compat->gpioz)
1080e569f6adSEtienne Carriere 		stm32mp_register_gpioz_pin_count(bank->ngpios);
1081e569f6adSEtienne Carriere 
10829818a481SEtienne Carriere 	*out_bank = bank;
1083bd03c8c3SGatien Chevallier 
10849818a481SEtienne Carriere 	return TEE_SUCCESS;
10859818a481SEtienne Carriere }
10869818a481SEtienne Carriere 
1087*a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_firewall_register(const void *fdt, int node,
1088*a650c9cbSEtienne Carriere 					       struct stm32_gpio_bank *bank)
1089*a650c9cbSEtienne Carriere {
1090*a650c9cbSEtienne Carriere 	struct firewall_controller *controller = NULL;
1091*a650c9cbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1092*a650c9cbSEtienne Carriere 	char bank_name[] = "gpio-bank-X";
1093*a650c9cbSEtienne Carriere 	char *name = NULL;
1094*a650c9cbSEtienne Carriere 
1095*a650c9cbSEtienne Carriere 	if (!IS_ENABLED(CFG_DRIVERS_FIREWALL) ||
1096*a650c9cbSEtienne Carriere 	    !bank->sec_support)
1097*a650c9cbSEtienne Carriere 		return TEE_SUCCESS;
1098*a650c9cbSEtienne Carriere 
1099*a650c9cbSEtienne Carriere 	controller = calloc(1, sizeof(*controller));
1100*a650c9cbSEtienne Carriere 	if (!controller)
1101*a650c9cbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
1102*a650c9cbSEtienne Carriere 
1103*a650c9cbSEtienne Carriere 	bank_name[sizeof(bank_name) - 2] = 'A' + bank->bank_id;
1104*a650c9cbSEtienne Carriere 	name = strdup(bank_name);
1105*a650c9cbSEtienne Carriere 
1106*a650c9cbSEtienne Carriere 	controller->name = name;
1107*a650c9cbSEtienne Carriere 	controller->priv = bank;
1108*a650c9cbSEtienne Carriere 	controller->ops = &stm32_gpio_firewall_ops;
1109*a650c9cbSEtienne Carriere 
1110*a650c9cbSEtienne Carriere 	if (!controller->name)
1111*a650c9cbSEtienne Carriere 		EMSG("Warning: out of memory to store bank name");
1112*a650c9cbSEtienne Carriere 
1113*a650c9cbSEtienne Carriere 	res = firewall_dt_controller_register(fdt, node, controller);
1114*a650c9cbSEtienne Carriere 	if (res) {
1115*a650c9cbSEtienne Carriere 		free(name);
1116*a650c9cbSEtienne Carriere 		free(controller);
1117*a650c9cbSEtienne Carriere 	}
1118*a650c9cbSEtienne Carriere 
1119*a650c9cbSEtienne Carriere 	return res;
1120*a650c9cbSEtienne Carriere }
1121*a650c9cbSEtienne Carriere 
1122bd03c8c3SGatien Chevallier /* Parse a pinctrl node to register the GPIO banks it describes */
11230e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
11249818a481SEtienne Carriere 					const void *compat_data)
11259818a481SEtienne Carriere {
11269818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
11279818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
11289818a481SEtienne Carriere 	int range_offs = 0;
11299818a481SEtienne Carriere 	int b_node = 0;
11309818a481SEtienne Carriere 	int len = 0;
11319818a481SEtienne Carriere 
11329818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
11339818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
11349818a481SEtienne Carriere 	if (!cuint)
11359818a481SEtienne Carriere 		panic("missing ranges property");
11369818a481SEtienne Carriere 
11379818a481SEtienne Carriere 	len /= sizeof(*cuint);
11389818a481SEtienne Carriere 	if (len == 3)
11399818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
11409818a481SEtienne Carriere 
11419818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
11429818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
11439818a481SEtienne Carriere 		if (cuint) {
11449818a481SEtienne Carriere 			/*
11459818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
11469818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
11479818a481SEtienne Carriere 			 * bank list.
11489818a481SEtienne Carriere 			 */
11499818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
11509818a481SEtienne Carriere 
11519818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
11529818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
11539818a481SEtienne Carriere 				continue;
11549818a481SEtienne Carriere 
11559818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
11569818a481SEtienne Carriere 						 range_offs, &bank);
11579818a481SEtienne Carriere 			if (res)
11589818a481SEtienne Carriere 				return res;
11599818a481SEtienne Carriere 
1160420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
1161420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
1162420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
1163420a32c5SEtienne Carriere 			if (res)
1164420a32c5SEtienne Carriere 				panic();
1165420a32c5SEtienne Carriere 
1166*a650c9cbSEtienne Carriere 			res = stm32_gpio_firewall_register(fdt, b_node, bank);
1167*a650c9cbSEtienne Carriere 			if (res)
1168*a650c9cbSEtienne Carriere 				panic();
1169*a650c9cbSEtienne Carriere 
11709818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
11719818a481SEtienne Carriere 		} else {
11729818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
11739818a481SEtienne Carriere 				panic();
11749818a481SEtienne Carriere 		}
11759818a481SEtienne Carriere 	}
11769818a481SEtienne Carriere 
11779818a481SEtienne Carriere 	return TEE_SUCCESS;
11789818a481SEtienne Carriere }
11799818a481SEtienne Carriere 
1180077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
1181077d486eSEtienne Carriere 			       bool secure)
11824b5e93edSEtienne Carriere {
1183077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
118498dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
11854b5e93edSEtienne Carriere 
1186077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
1187077d486eSEtienne Carriere 		panic();
118898dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
11894b5e93edSEtienne Carriere 
11904b5e93edSEtienne Carriere 	if (secure)
1191077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
11924b5e93edSEtienne Carriere 	else
1193077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
11944b5e93edSEtienne Carriere 
1195c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
119698dfcedaSEtienne Carriere 	clk_disable(bank->clock);
11974b5e93edSEtienne Carriere }
11980e0435e2SEtienne Carriere 
1199b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1200b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
1201b38386fbSEtienne Carriere {
1202b38386fbSEtienne Carriere 	struct stm32_pinctrl_array *ref = conf->priv;
1203b38386fbSEtienne Carriere 	struct stm32_pinctrl *p = ref->pinctrl;
1204b38386fbSEtienne Carriere 	size_t pin_count = ref->count;
1205b38386fbSEtienne Carriere 	size_t n = 0;
1206b38386fbSEtienne Carriere 
1207b38386fbSEtienne Carriere 	for (n = 0; n < pin_count; n++)
1208b38386fbSEtienne Carriere 		set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
1209b38386fbSEtienne Carriere 
1210b38386fbSEtienne Carriere 	return TEE_SUCCESS;
1211b38386fbSEtienne Carriere }
1212b38386fbSEtienne Carriere 
1213b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
1214b38386fbSEtienne Carriere {
1215b38386fbSEtienne Carriere 	free(conf);
1216b38386fbSEtienne Carriere }
1217b38386fbSEtienne Carriere 
1218b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
1219b38386fbSEtienne Carriere 	.conf_apply = stm32_pinctrl_conf_apply,
1220b38386fbSEtienne Carriere 	.conf_free = stm32_pinctrl_conf_free,
1221b38386fbSEtienne Carriere };
1222b38386fbSEtienne Carriere 
1223b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
1224b38386fbSEtienne Carriere 
122570ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
122670ac0db5SEtienne Carriere 				 unsigned int *bank, unsigned int *pin,
122770ac0db5SEtienne Carriere 				 unsigned int *count)
122870ac0db5SEtienne Carriere {
122970ac0db5SEtienne Carriere 	size_t conf_index = 0;
123070ac0db5SEtienne Carriere 	size_t pin_count = 0;
123170ac0db5SEtienne Carriere 	size_t n = 0;
123270ac0db5SEtienne Carriere 
123370ac0db5SEtienne Carriere 	assert(count);
123470ac0db5SEtienne Carriere 	if (!pinctrl)
123570ac0db5SEtienne Carriere 		goto out;
123670ac0db5SEtienne Carriere 
123770ac0db5SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
123870ac0db5SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
123970ac0db5SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
124070ac0db5SEtienne Carriere 
124170ac0db5SEtienne Carriere 		/* Consider only the stm32_gpio pins */
124270ac0db5SEtienne Carriere 		if (pinconf->ops != &stm32_pinctrl_ops)
124370ac0db5SEtienne Carriere 			continue;
124470ac0db5SEtienne Carriere 
124570ac0db5SEtienne Carriere 		if (bank || pin) {
124670ac0db5SEtienne Carriere 			for (n = 0; n < ref->count; n++) {
124770ac0db5SEtienne Carriere 				if (bank && pin_count < *count)
124870ac0db5SEtienne Carriere 					bank[pin_count] = ref->pinctrl[n].bank;
124970ac0db5SEtienne Carriere 				if (pin && pin_count < *count)
125070ac0db5SEtienne Carriere 					pin[pin_count] = ref->pinctrl[n].pin;
125170ac0db5SEtienne Carriere 				pin_count++;
125270ac0db5SEtienne Carriere 			}
125370ac0db5SEtienne Carriere 		} else {
125470ac0db5SEtienne Carriere 			pin_count += ref->count;
125570ac0db5SEtienne Carriere 		}
125670ac0db5SEtienne Carriere 	}
125770ac0db5SEtienne Carriere 
125870ac0db5SEtienne Carriere out:
125970ac0db5SEtienne Carriere 	*count = pin_count;
126070ac0db5SEtienne Carriere }
126170ac0db5SEtienne Carriere 
12627f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure)
12637f823a77SEtienne Carriere {
12647f823a77SEtienne Carriere 	size_t conf_index = 0;
12657f823a77SEtienne Carriere 
12667f823a77SEtienne Carriere 	if (!pinctrl)
12677f823a77SEtienne Carriere 		return;
12687f823a77SEtienne Carriere 
12697f823a77SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
12707f823a77SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
12717f823a77SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
12727f823a77SEtienne Carriere 		struct stm32_pinctrl *pc = NULL;
12737f823a77SEtienne Carriere 		size_t n = 0;
12747f823a77SEtienne Carriere 
12757f823a77SEtienne Carriere 		for (n = 0; n < ref->count; n++) {
12767f823a77SEtienne Carriere 			if (pinconf->ops != &stm32_pinctrl_ops)
12777f823a77SEtienne Carriere 				continue;
12787f823a77SEtienne Carriere 
12797f823a77SEtienne Carriere 			pc = ref->pinctrl + n;
12807f823a77SEtienne Carriere 			stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure);
12817f823a77SEtienne Carriere 		}
12827f823a77SEtienne Carriere 	}
12837f823a77SEtienne Carriere }
12847f823a77SEtienne Carriere 
1285b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
1286b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
1287b38386fbSEtienne Carriere 				       void *data __unused,
1288b38386fbSEtienne Carriere 				       struct pinconf **out_pinconf)
1289b38386fbSEtienne Carriere {
1290b38386fbSEtienne Carriere 	struct conf {
1291b38386fbSEtienne Carriere 		struct pinconf pinconf;
1292b38386fbSEtienne Carriere 		struct stm32_pinctrl_array array_ref;
1293b38386fbSEtienne Carriere 	} *loc_conf = NULL;
1294b38386fbSEtienne Carriere 	struct stm32_pinctrl *pinctrl = NULL;
1295b38386fbSEtienne Carriere 	struct pinconf *pinconf = NULL;
1296b38386fbSEtienne Carriere 	const void *fdt = NULL;
1297b38386fbSEtienne Carriere 	size_t pin_count = 0;
1298b38386fbSEtienne Carriere 	int pinctrl_node = 0;
1299b38386fbSEtienne Carriere 	int pinmux_node = 0;
1300b38386fbSEtienne Carriere 	int count = 0;
1301b38386fbSEtienne Carriere 
1302b38386fbSEtienne Carriere 	pinctrl_node = pargs->phandle_node;
1303b38386fbSEtienne Carriere 	fdt = pargs->fdt;
1304b38386fbSEtienne Carriere 	assert(fdt && pinctrl_node);
1305b38386fbSEtienne Carriere 
1306b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1307b38386fbSEtienne Carriere 		if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
1308b38386fbSEtienne Carriere 			pin_count += (size_t)count / sizeof(uint32_t);
1309b38386fbSEtienne Carriere 		else if (count != -FDT_ERR_NOTFOUND)
1310b38386fbSEtienne Carriere 			panic();
1311b38386fbSEtienne Carriere 	}
1312b38386fbSEtienne Carriere 
1313b38386fbSEtienne Carriere 	loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
1314b38386fbSEtienne Carriere 	if (!loc_conf)
1315b38386fbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
1316b38386fbSEtienne Carriere 
1317b38386fbSEtienne Carriere 	pinconf = &loc_conf->pinconf;
1318b38386fbSEtienne Carriere 	pinconf->ops = &stm32_pinctrl_ops;
1319b38386fbSEtienne Carriere 	pinconf->priv = &loc_conf->array_ref;
1320b38386fbSEtienne Carriere 
1321b38386fbSEtienne Carriere 	loc_conf->array_ref.count = pin_count;
1322b38386fbSEtienne Carriere 	pinctrl = loc_conf->array_ref.pinctrl;
1323b38386fbSEtienne Carriere 
1324b38386fbSEtienne Carriere 	count = 0;
1325b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1326b38386fbSEtienne Carriere 		int found = 0;
1327b38386fbSEtienne Carriere 
1328b38386fbSEtienne Carriere 		found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count,
1329b38386fbSEtienne Carriere 					     pin_count - count);
1330b38386fbSEtienne Carriere 		if (found <= 0 && found > ((int)pin_count - count)) {
1331b38386fbSEtienne Carriere 			/* We can't recover from an error here so let's panic */
1332b38386fbSEtienne Carriere 			panic();
1333b38386fbSEtienne Carriere 		}
1334b38386fbSEtienne Carriere 
1335b38386fbSEtienne Carriere 		count += found;
1336b38386fbSEtienne Carriere 	}
1337b38386fbSEtienne Carriere 
1338b38386fbSEtienne Carriere 	*out_pinconf = pinconf;
1339b38386fbSEtienne Carriere 
1340b38386fbSEtienne Carriere 	return TEE_SUCCESS;
1341b38386fbSEtienne Carriere }
1342b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
1343b38386fbSEtienne Carriere 
1344bfc43b68SGatien Chevallier static void stm32_gpio_get_conf_sec(struct stm32_gpio_bank *bank)
1345bfc43b68SGatien Chevallier {
1346bfc43b68SGatien Chevallier 	if (bank->sec_support) {
1347bfc43b68SGatien Chevallier 		clk_enable(bank->clock);
1348bfc43b68SGatien Chevallier 		bank->seccfgr = io_read32(bank->base + GPIO_SECR_OFFSET);
1349bfc43b68SGatien Chevallier 		clk_disable(bank->clock);
1350bfc43b68SGatien Chevallier 	}
1351bfc43b68SGatien Chevallier }
1352bfc43b68SGatien Chevallier 
1353bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank)
1354bd03c8c3SGatien Chevallier {
1355bd03c8c3SGatien Chevallier 	if (bank->sec_support) {
1356bd03c8c3SGatien Chevallier 		clk_enable(bank->clock);
1357bd03c8c3SGatien Chevallier 		io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr);
1358bd03c8c3SGatien Chevallier 		clk_disable(bank->clock);
1359bd03c8c3SGatien Chevallier 	}
1360bd03c8c3SGatien Chevallier }
1361bd03c8c3SGatien Chevallier 
1362bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_resume(void)
1363bfc43b68SGatien Chevallier {
1364bfc43b68SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1365bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1366bfc43b68SGatien Chevallier 
1367bfc43b68SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1368bfc43b68SGatien Chevallier 		if (bank->rif_cfg) {
1369bfc43b68SGatien Chevallier 			if (!bank->is_tdcid)
1370bfc43b68SGatien Chevallier 				continue;
1371bfc43b68SGatien Chevallier 
1372bfc43b68SGatien Chevallier 			bank->rif_cfg->access_mask[0] = GENMASK_32(bank->ngpios,
1373bfc43b68SGatien Chevallier 								   0);
1374bfc43b68SGatien Chevallier 
1375a72f07daSEtienne Carriere 			res = apply_rif_config(bank,
1376a72f07daSEtienne Carriere 					       bank->rif_cfg->access_mask[0]);
1377bfc43b68SGatien Chevallier 			if (res) {
1378bfc43b68SGatien Chevallier 				EMSG("Failed to set GPIO bank %c RIF config",
1379bfc43b68SGatien Chevallier 				     'A' + bank->bank_id);
1380bfc43b68SGatien Chevallier 				return res;
1381bfc43b68SGatien Chevallier 			}
1382bfc43b68SGatien Chevallier 		} else {
1383bfc43b68SGatien Chevallier 			stm32_gpio_set_conf_sec(bank);
1384bfc43b68SGatien Chevallier 		}
1385bfc43b68SGatien Chevallier 	}
1386bfc43b68SGatien Chevallier 
1387bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
1388bfc43b68SGatien Chevallier }
1389bfc43b68SGatien Chevallier 
1390bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_suspend(void)
1391bfc43b68SGatien Chevallier {
1392bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1393bfc43b68SGatien Chevallier 
1394bfc43b68SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1395bfc43b68SGatien Chevallier 		if (bank->rif_cfg) {
1396bfc43b68SGatien Chevallier 			if (bank->is_tdcid)
1397bfc43b68SGatien Chevallier 				stm32_gpio_save_rif_config(bank);
1398bfc43b68SGatien Chevallier 		} else {
1399bfc43b68SGatien Chevallier 			stm32_gpio_get_conf_sec(bank);
1400bfc43b68SGatien Chevallier 		}
1401bfc43b68SGatien Chevallier 	}
1402bfc43b68SGatien Chevallier 
1403bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
1404bfc43b68SGatien Chevallier }
1405bfc43b68SGatien Chevallier 
1406bfc43b68SGatien Chevallier static TEE_Result
1407bfc43b68SGatien Chevallier stm32_gpio_sec_config_pm(enum pm_op op, unsigned int pm_hint,
1408bfc43b68SGatien Chevallier 			 const struct pm_callback_handle *hdl __unused)
1409bfc43b68SGatien Chevallier {
1410bfc43b68SGatien Chevallier 	TEE_Result ret = TEE_ERROR_GENERIC;
1411bfc43b68SGatien Chevallier 
1412bfc43b68SGatien Chevallier 	if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
1413bfc43b68SGatien Chevallier 		return TEE_SUCCESS;
1414bfc43b68SGatien Chevallier 
1415bfc43b68SGatien Chevallier 	if (op == PM_OP_RESUME)
1416bfc43b68SGatien Chevallier 		ret = stm32_gpio_sec_config_resume();
1417bfc43b68SGatien Chevallier 	else
1418bfc43b68SGatien Chevallier 		ret = stm32_gpio_sec_config_suspend();
1419bfc43b68SGatien Chevallier 
1420bfc43b68SGatien Chevallier 	return ret;
1421bfc43b68SGatien Chevallier }
1422bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(stm32_gpio_sec_config_pm);
1423bfc43b68SGatien Chevallier 
1424bd03c8c3SGatien Chevallier /*
1425bd03c8c3SGatien Chevallier  * Several pinctrl nodes can be probed. Their bank will be put in the unique
1426bd03c8c3SGatien Chevallier  * bank_list. To avoid multiple configuration set for a bank when looping
1427bd03c8c3SGatien Chevallier  * over each bank in the bank list, ready is set to true when a bank is
1428bd03c8c3SGatien Chevallier  * configured. Therefore, during other bank probes, the configuration won't
1429bd03c8c3SGatien Chevallier  * be set again.
1430bd03c8c3SGatien Chevallier  */
1431bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void)
1432bd03c8c3SGatien Chevallier {
1433bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1434bd03c8c3SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1435bd03c8c3SGatien Chevallier 
1436bd03c8c3SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1437bd03c8c3SGatien Chevallier 		if (bank->ready)
1438bd03c8c3SGatien Chevallier 			continue;
1439bd03c8c3SGatien Chevallier 
1440bd03c8c3SGatien Chevallier 		if (bank->rif_cfg) {
1441a72f07daSEtienne Carriere 			res = apply_rif_config(bank,
1442a72f07daSEtienne Carriere 					       bank->rif_cfg->access_mask[0]);
1443bd03c8c3SGatien Chevallier 			if (res) {
1444bd03c8c3SGatien Chevallier 				EMSG("Failed to set GPIO bank %c RIF config",
1445bd03c8c3SGatien Chevallier 				     'A' + bank->bank_id);
1446bd03c8c3SGatien Chevallier 				STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank,
1447bd03c8c3SGatien Chevallier 					      link);
14489def1fb7SGatien Chevallier 				free(bank);
1449bd03c8c3SGatien Chevallier 				return res;
1450bd03c8c3SGatien Chevallier 			}
1451bd03c8c3SGatien Chevallier 		} else {
1452bd03c8c3SGatien Chevallier 			stm32_gpio_set_conf_sec(bank);
1453bd03c8c3SGatien Chevallier 		}
1454bd03c8c3SGatien Chevallier 
1455bd03c8c3SGatien Chevallier 		bank->ready = true;
1456bd03c8c3SGatien Chevallier 	}
1457bd03c8c3SGatien Chevallier 
1458bd03c8c3SGatien Chevallier 	return TEE_SUCCESS;
1459bd03c8c3SGatien Chevallier }
1460bd03c8c3SGatien Chevallier 
14610e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
14620e0435e2SEtienne Carriere 				      const void *compat_data)
14630e0435e2SEtienne Carriere {
1464bfc43b68SGatien Chevallier 	static bool pm_register;
1465b38386fbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1466b38386fbSEtienne Carriere 
14670e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
1468b38386fbSEtienne Carriere 	res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
1469b38386fbSEtienne Carriere 	if (res)
1470b38386fbSEtienne Carriere 		return res;
1471b38386fbSEtienne Carriere 
1472bd03c8c3SGatien Chevallier 	if (STAILQ_EMPTY(&bank_list))
1473bd03c8c3SGatien Chevallier 		DMSG("no gpio bank for that driver");
1474bd03c8c3SGatien Chevallier 	else if (apply_sec_cfg())
1475bd03c8c3SGatien Chevallier 		panic();
1476bd03c8c3SGatien Chevallier 
1477bfc43b68SGatien Chevallier 	if (!pm_register) {
1478bfc43b68SGatien Chevallier 		/*
1479bfc43b68SGatien Chevallier 		 * Register to PM once for all probed banks to restore
1480bfc43b68SGatien Chevallier 		 * their secure configuration.
1481bfc43b68SGatien Chevallier 		 */
1482bfc43b68SGatien Chevallier 		register_pm_driver_cb(stm32_gpio_sec_config_pm, NULL,
1483bfc43b68SGatien Chevallier 				      "stm32-gpio-secure-config");
1484bfc43b68SGatien Chevallier 		pm_register = true;
1485bfc43b68SGatien Chevallier 	}
1486bfc43b68SGatien Chevallier 
1487b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1488b38386fbSEtienne Carriere 	res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
1489b38386fbSEtienne Carriere 					(void *)compat_data);
1490b38386fbSEtienne Carriere 	if (res)
1491bd03c8c3SGatien Chevallier 		panic();
1492b38386fbSEtienne Carriere #endif
1493b38386fbSEtienne Carriere 
1494b38386fbSEtienne Carriere 	return TEE_SUCCESS;
14950e0435e2SEtienne Carriere }
14960e0435e2SEtienne Carriere 
14970e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
1498e569f6adSEtienne Carriere 	{
1499e569f6adSEtienne Carriere 		.compatible = "st,stm32mp135-pinctrl",
1500b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1501b4893304SGatien Chevallier 			.secure_control = true,
1502bd03c8c3SGatien Chevallier 			.secure_extended = false,
1503b4893304SGatien Chevallier 		},
1504e569f6adSEtienne Carriere 	},
1505e569f6adSEtienne Carriere 	{
1506e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-pinctrl",
1507b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1508b4893304SGatien Chevallier 			.secure_control = false,
1509bd03c8c3SGatien Chevallier 			.secure_extended = false,
1510b4893304SGatien Chevallier 		},
1511e569f6adSEtienne Carriere 	},
1512e569f6adSEtienne Carriere 	{
1513e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-z-pinctrl",
1514b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1515b4893304SGatien Chevallier 			.gpioz = true,
1516b4893304SGatien Chevallier 			.secure_control = true,
1517bd03c8c3SGatien Chevallier 			.secure_extended = false,
1518bd03c8c3SGatien Chevallier 		},
1519bd03c8c3SGatien Chevallier 	},
1520bd03c8c3SGatien Chevallier 	{
1521bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-pinctrl",
1522bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1523bd03c8c3SGatien Chevallier 			.secure_control = true,
1524bd03c8c3SGatien Chevallier 			.secure_extended = true,
1525bd03c8c3SGatien Chevallier 		},
1526bd03c8c3SGatien Chevallier 	},
1527bd03c8c3SGatien Chevallier 	{
1528bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-z-pinctrl",
1529bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1530bd03c8c3SGatien Chevallier 			.gpioz = true,
1531bd03c8c3SGatien Chevallier 			.secure_control = true,
1532bd03c8c3SGatien Chevallier 			.secure_extended = true,
1533b4893304SGatien Chevallier 		},
1534e569f6adSEtienne Carriere 	},
15350e0435e2SEtienne Carriere 	{ }
15360e0435e2SEtienne Carriere };
15370e0435e2SEtienne Carriere 
15380e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
15390e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
15400e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
15410e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
15420e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
15430e0435e2SEtienne Carriere };
1544