xref: /optee_os/core/drivers/stm32_gpio.c (revision a72f07dabc4dd94663d059299b509a955f17f1a6)
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>
12420a32c5SEtienne Carriere #include <drivers/gpio.h>
13b38386fbSEtienne Carriere #include <drivers/pinctrl.h>
144b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h>
15bd03c8c3SGatien Chevallier #include <drivers/stm32_rif.h>
16bd03c8c3SGatien Chevallier #include <dt-bindings/gpio/gpio.h>
174b5e93edSEtienne Carriere #include <io.h>
184b5e93edSEtienne Carriere #include <kernel/dt.h>
1965401337SJens Wiklander #include <kernel/boot.h>
204b5e93edSEtienne Carriere #include <kernel/panic.h>
21bfc43b68SGatien Chevallier #include <kernel/pm.h>
224b5e93edSEtienne Carriere #include <kernel/spinlock.h>
23a2fc83d1SJerome Forissier #include <libfdt.h>
244b5e93edSEtienne Carriere #include <mm/core_memprot.h>
254b5e93edSEtienne Carriere #include <stdbool.h>
2669715ce9SEtienne Carriere #include <stdint.h>
274b5e93edSEtienne Carriere #include <stm32_util.h>
289818a481SEtienne Carriere #include <sys/queue.h>
294b5e93edSEtienne Carriere #include <trace.h>
304b5e93edSEtienne Carriere #include <util.h>
314b5e93edSEtienne Carriere 
321001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO
331001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO
341001585eSEtienne Carriere #endif
351001585eSEtienne Carriere 
364b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
374b5e93edSEtienne Carriere 
385eed568cSGatien Chevallier #define GPIO_MODER_OFFSET	U(0x00)
395eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET	U(0x04)
405eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET	U(0x08)
415eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET	U(0x0c)
425eed568cSGatien Chevallier #define GPIO_IDR_OFFSET		U(0x10)
435eed568cSGatien Chevallier #define GPIO_ODR_OFFSET		U(0x14)
445eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET	U(0x18)
455eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET	U(0x20)
465eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET	U(0x24)
475eed568cSGatien Chevallier #define GPIO_SECR_OFFSET	U(0x30)
48bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET	U(0x34)
49bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET	U(0x38)
50bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x)		(U(0x50) + U(0x8) * (x))
51bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x)		(U(0x54) + U(0x8) * (x))
524b5e93edSEtienne Carriere 
535eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT	U(0x8)
544b5e93edSEtienne Carriere 
55bd03c8c3SGatien Chevallier /*
56bd03c8c3SGatien Chevallier  * CIDCFGR register bitfields
57bd03c8c3SGatien Chevallier  */
58bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK	GENMASK_32(23, 16)
59bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK	GENMASK_32(6, 4)
60bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK	(_CIDCFGR_CFEN | _CIDCFGR_SEMEN |	\
61bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SCID_MASK |		\
62bd03c8c3SGatien Chevallier 				 GPIO_CIDCFGR_SEMWL_MASK)
63bd03c8c3SGatien Chevallier 
64bd03c8c3SGatien Chevallier /*
65bd03c8c3SGatien Chevallier  * PRIVCFGR register bitfields
66bd03c8c3SGatien Chevallier  */
67bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK	GENMASK_32(15, 0)
68bd03c8c3SGatien Chevallier 
69bd03c8c3SGatien Chevallier /*
70bd03c8c3SGatien Chevallier  * SECCFGR register bitfields
71bd03c8c3SGatien Chevallier  */
72bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK	GENMASK_32(15, 0)
73bd03c8c3SGatien Chevallier 
74bd03c8c3SGatien Chevallier /*
75bd03c8c3SGatien Chevallier  * RCFGLOCKR register bitfields
76bd03c8c3SGatien Chevallier  */
77bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK	GENMASK_32(15, 0)
78bd03c8c3SGatien Chevallier 
79bd03c8c3SGatien Chevallier /*
80bd03c8c3SGatien Chevallier  * SEMCR register bitfields
81bd03c8c3SGatien Chevallier  */
82bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M	GENMASK_32(6, 4)
83bd03c8c3SGatien Chevallier 
844b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
854b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
864b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
87729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
884b5e93edSEtienne Carriere 
895eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT	U(12)
904b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
915eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT	U(8)
924b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
934b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
944b5e93edSEtienne Carriere 
959818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0	"GPIOA"
969818a481SEtienne Carriere 
9769715ce9SEtienne Carriere #define GPIO_MODE_INPUT		U(0x0)
9869715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT	U(0x1)
9969715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE	U(0x2)
10069715ce9SEtienne Carriere #define GPIO_MODE_ANALOG	U(0x3)
10169715ce9SEtienne Carriere 
10269715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL	U(0x0)
10369715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN	U(0x1)
10469715ce9SEtienne Carriere 
10569715ce9SEtienne Carriere #define GPIO_OSPEED_LOW		U(0x0)
10669715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM	U(0x1)
10769715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH	U(0x2)
10869715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH	U(0x3)
10969715ce9SEtienne Carriere 
11069715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL	U(0x0)
11169715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP	U(0x1)
11269715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN	U(0x2)
11369715ce9SEtienne Carriere 
11469715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW	U(0x0)
11569715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH	U(0x1)
11669715ce9SEtienne Carriere 
117bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED	U(3)
118bd03c8c3SGatien Chevallier 
11969715ce9SEtienne Carriere /*
12069715ce9SEtienne Carriere  * GPIO configuration description structured as single 16bit word
12169715ce9SEtienne Carriere  * for efficient save/restore when GPIO pin suspends or resumes.
12269715ce9SEtienne Carriere  *
12369715ce9SEtienne Carriere  * @mode: One of GPIO_MODE_*
12469715ce9SEtienne Carriere  * @otype: One of GPIO_OTYPE_*
12569715ce9SEtienne Carriere  * @ospeed: One of GPIO_OSPEED_*
12669715ce9SEtienne Carriere  * @pupd: One of GPIO_PUPD_*
12769715ce9SEtienne Carriere  * @od: One of GPIO_OD_*
12869715ce9SEtienne Carriere  * @af: Alternate function numerical ID between 0 and 15
12969715ce9SEtienne Carriere  */
13069715ce9SEtienne Carriere struct gpio_cfg {
13169715ce9SEtienne Carriere 	uint16_t mode:		2;
13269715ce9SEtienne Carriere 	uint16_t otype:		1;
13369715ce9SEtienne Carriere 	uint16_t ospeed:	2;
13469715ce9SEtienne Carriere 	uint16_t pupd:		2;
13569715ce9SEtienne Carriere 	uint16_t od:		1;
13669715ce9SEtienne Carriere 	uint16_t af:		4;
13769715ce9SEtienne Carriere };
13869715ce9SEtienne Carriere 
13969715ce9SEtienne Carriere /*
14069715ce9SEtienne Carriere  * Description of a pin and its muxing
14169715ce9SEtienne Carriere  *
14269715ce9SEtienne Carriere  * @bank: GPIO bank identifier as assigned by the platform
14369715ce9SEtienne Carriere  * @pin: Pin number in the GPIO bank
14469715ce9SEtienne Carriere  * @cfg: Pin configuration
14569715ce9SEtienne Carriere  */
14669715ce9SEtienne Carriere struct stm32_pinctrl {
14769715ce9SEtienne Carriere 	uint8_t bank;
14869715ce9SEtienne Carriere 	uint8_t pin;
14969715ce9SEtienne Carriere 	struct gpio_cfg cfg;
15069715ce9SEtienne Carriere };
15169715ce9SEtienne Carriere 
152b38386fbSEtienne Carriere /*
153b38386fbSEtienne Carriere  * struct stm32_pinctrl_array - Array of pins in a pin control state
154b38386fbSEtienne Carriere  * @count: Number of cells in @pinctrl
155b38386fbSEtienne Carriere  * @pinctrl: Pin control configuration
156b38386fbSEtienne Carriere  */
157b38386fbSEtienne Carriere struct stm32_pinctrl_array {
158b38386fbSEtienne Carriere 	size_t count;
159b38386fbSEtienne Carriere 	struct stm32_pinctrl pinctrl[];
160b38386fbSEtienne Carriere };
161b38386fbSEtienne Carriere 
1629818a481SEtienne Carriere /**
1639818a481SEtienne Carriere  * struct stm32_gpio_bank - GPIO bank instance
1649818a481SEtienne Carriere  *
1659818a481SEtienne Carriere  * @base: base address of the GPIO controller registers.
1669818a481SEtienne Carriere  * @clock: clock identifier.
167420a32c5SEtienne Carriere  * @gpio_chip: GPIO chip reference for that GPIO bank
1689818a481SEtienne Carriere  * @ngpios: number of GPIOs.
1699818a481SEtienne Carriere  * @bank_id: Id of the bank.
1709818a481SEtienne Carriere  * @lock: lock protecting the GPIO bank access.
171bd03c8c3SGatien Chevallier  * @rif_cfg: RIF configuration data
172bd03c8c3SGatien Chevallier  * @seccfgr: non-RIF bank secure configuration data
173bd03c8c3SGatien Chevallier  * @sec_support: True if bank supports pin security protection, else false
174bd03c8c3SGatien Chevallier  * @ready: True if configuration is applied, else false
175bd03c8c3SGatien Chevallier  * @is_tdcid: True if OP-TEE runs as Trusted Domain CID
1769818a481SEtienne Carriere  * @link: Link in bank list
1779818a481SEtienne Carriere  */
1789818a481SEtienne Carriere struct stm32_gpio_bank {
1799818a481SEtienne Carriere 	vaddr_t base;
1809818a481SEtienne Carriere 	struct clk *clock;
181420a32c5SEtienne Carriere 	struct gpio_chip gpio_chip;
1829818a481SEtienne Carriere 	unsigned int ngpios;
1839818a481SEtienne Carriere 	unsigned int bank_id;
1849818a481SEtienne Carriere 	unsigned int lock;
185bd03c8c3SGatien Chevallier 	struct rif_conf_data *rif_cfg;
186bd03c8c3SGatien Chevallier 	uint32_t seccfgr;
187b4893304SGatien Chevallier 	bool sec_support;
188bd03c8c3SGatien Chevallier 	bool ready;
189bd03c8c3SGatien Chevallier 	bool is_tdcid;
1909818a481SEtienne Carriere 	STAILQ_ENTRY(stm32_gpio_bank) link;
1919818a481SEtienne Carriere };
1929818a481SEtienne Carriere 
193bfc43b68SGatien Chevallier /*
194bfc43b68SGatien Chevallier  * struct stm32_gpio_pm_state - Consumed GPIO for PM purpose
195bfc43b68SGatien Chevallier  * @gpio_pinctrl: Reference and configuration state for a consumed GPIO
196bfc43b68SGatien Chevallier  * @level: GPIO level
197bfc43b68SGatien Chevallier  * @link: Link in consumed GPIO list
198bfc43b68SGatien Chevallier  */
199bfc43b68SGatien Chevallier struct stm32_gpio_pm_state {
200bfc43b68SGatien Chevallier 	struct stm32_pinctrl gpio_pinctrl;
201bfc43b68SGatien Chevallier 	uint8_t level;
202bfc43b68SGatien Chevallier 	SLIST_ENTRY(stm32_gpio_pm_state) link;
203bfc43b68SGatien Chevallier };
204bfc43b68SGatien Chevallier 
205b4893304SGatien Chevallier /**
206e569f6adSEtienne Carriere  * Compatibility information of supported banks
207b4893304SGatien Chevallier  *
208b4893304SGatien Chevallier  * @gpioz: True if bank is a GPIOZ bank
209b4893304SGatien Chevallier  * @secure_control: Identify GPIO security bank capability.
210bd03c8c3SGatien Chevallier  * @secure_extended: Identify RIF presence.
211e569f6adSEtienne Carriere  */
212e569f6adSEtienne Carriere struct bank_compat {
213e569f6adSEtienne Carriere 	bool gpioz;
214b4893304SGatien Chevallier 	bool secure_control;
215bd03c8c3SGatien Chevallier 	bool secure_extended;
216e569f6adSEtienne Carriere };
217e569f6adSEtienne Carriere 
2184b5e93edSEtienne Carriere static unsigned int gpio_lock;
2194b5e93edSEtienne Carriere 
2209818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
2219818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
2229818a481SEtienne Carriere 
223bfc43b68SGatien Chevallier static SLIST_HEAD(, stm32_gpio_pm_state) consumed_gpios_head;
224bfc43b68SGatien Chevallier 
225420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
226420a32c5SEtienne Carriere 
227420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
228420a32c5SEtienne Carriere {
229420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
230420a32c5SEtienne Carriere }
231420a32c5SEtienne Carriere 
232420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
233420a32c5SEtienne Carriere 					    unsigned int gpio_pin)
234420a32c5SEtienne Carriere {
235420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
236420a32c5SEtienne Carriere 	enum gpio_level level = GPIO_LEVEL_HIGH;
237420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
238420a32c5SEtienne Carriere 	unsigned int mode = 0;
239420a32c5SEtienne Carriere 
240420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2412fd102ebSEtienne Carriere 
2422fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2432fd102ebSEtienne Carriere 		panic();
244420a32c5SEtienne Carriere 
245420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
246420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
247420a32c5SEtienne Carriere 
248420a32c5SEtienne Carriere 	switch (mode) {
249420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
250420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
251420a32c5SEtienne Carriere 		break;
252420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
253420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
254420a32c5SEtienne Carriere 		break;
255420a32c5SEtienne Carriere 	default:
256420a32c5SEtienne Carriere 		panic();
257420a32c5SEtienne Carriere 	}
258420a32c5SEtienne Carriere 
259420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
260420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
261420a32c5SEtienne Carriere 	else
262420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
263420a32c5SEtienne Carriere 
264420a32c5SEtienne Carriere 	clk_disable(bank->clock);
265420a32c5SEtienne Carriere 
266420a32c5SEtienne Carriere 	return level;
267420a32c5SEtienne Carriere }
268420a32c5SEtienne Carriere 
269420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
270420a32c5SEtienne Carriere 				 enum gpio_level level)
271420a32c5SEtienne Carriere {
272420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
273420a32c5SEtienne Carriere 
274420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2752fd102ebSEtienne Carriere 
2762fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2772fd102ebSEtienne Carriere 		panic();
278420a32c5SEtienne Carriere 
279420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
280420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
281420a32c5SEtienne Carriere 
282420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
283420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
284420a32c5SEtienne Carriere 	else
285420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
286420a32c5SEtienne Carriere 
287420a32c5SEtienne Carriere 	clk_disable(bank->clock);
288420a32c5SEtienne Carriere }
289420a32c5SEtienne Carriere 
290420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
291420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
292420a32c5SEtienne Carriere {
293420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
294420a32c5SEtienne Carriere 	uint32_t mode = 0;
295420a32c5SEtienne Carriere 
296420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2972fd102ebSEtienne Carriere 
2982fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2992fd102ebSEtienne Carriere 		panic();
300420a32c5SEtienne Carriere 
301420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
302420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
303420a32c5SEtienne Carriere 
304420a32c5SEtienne Carriere 	clk_disable(bank->clock);
305420a32c5SEtienne Carriere 
306420a32c5SEtienne Carriere 	switch (mode) {
307420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
308420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
309420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
310420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
311420a32c5SEtienne Carriere 	default:
312420a32c5SEtienne Carriere 		panic();
313420a32c5SEtienne Carriere 	}
314420a32c5SEtienne Carriere }
315420a32c5SEtienne Carriere 
316420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
317420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
318420a32c5SEtienne Carriere 				     enum gpio_dir direction)
319420a32c5SEtienne Carriere {
320420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
321420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
322420a32c5SEtienne Carriere 	uint32_t mode = 0;
323420a32c5SEtienne Carriere 
324420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
325420a32c5SEtienne Carriere 
326420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
327420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
328420a32c5SEtienne Carriere 	else
329420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
330420a32c5SEtienne Carriere 
3312fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
3322fd102ebSEtienne Carriere 		panic();
333420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
334420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
335420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
336420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
337420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
338420a32c5SEtienne Carriere 	clk_disable(bank->clock);
339420a32c5SEtienne Carriere }
340420a32c5SEtienne Carriere 
341bfc43b68SGatien Chevallier /* Forward reference to the PM callback handler for consumed GPIOs */
342bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, unsigned int pm_hint,
343bfc43b68SGatien Chevallier 				    const struct pm_callback_handle *pm_hdl);
344bfc43b68SGatien Chevallier 
345bfc43b68SGatien Chevallier static void stm32_gpio_put_gpio(struct gpio_chip *chip, struct gpio *gpio)
346420a32c5SEtienne Carriere {
347bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
348bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *tstate = NULL;
349bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *state = NULL;
350bfc43b68SGatien Chevallier 	uint32_t exceptions = 0;
351bfc43b68SGatien Chevallier 
352420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
353bfc43b68SGatien Chevallier 
354bfc43b68SGatien Chevallier 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
355bfc43b68SGatien Chevallier 
356bfc43b68SGatien Chevallier 	SLIST_FOREACH_SAFE(state, &consumed_gpios_head, link, tstate) {
357bfc43b68SGatien Chevallier 		if (state->gpio_pinctrl.bank == bank->bank_id &&
358bfc43b68SGatien Chevallier 		    state->gpio_pinctrl.pin == gpio->pin) {
359bfc43b68SGatien Chevallier 			SLIST_REMOVE(&consumed_gpios_head, state,
360bfc43b68SGatien Chevallier 				     stm32_gpio_pm_state, link);
361bfc43b68SGatien Chevallier 			unregister_pm_driver_cb(consumed_gpios_pm, state);
362bfc43b68SGatien Chevallier 			free(state);
363420a32c5SEtienne Carriere 			free(gpio);
364bfc43b68SGatien Chevallier 			break;
365bfc43b68SGatien Chevallier 		}
366bfc43b68SGatien Chevallier 	}
367bfc43b68SGatien Chevallier 	assert(state);
368bfc43b68SGatien Chevallier 
369bfc43b68SGatien Chevallier 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
370420a32c5SEtienne Carriere }
371420a32c5SEtienne Carriere 
372420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
373420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
374420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
375420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
376420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
377420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
378420a32c5SEtienne Carriere };
379420a32c5SEtienne Carriere 
380420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
381420a32c5SEtienne Carriere {
382420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
383420a32c5SEtienne Carriere }
384420a32c5SEtienne Carriere 
385077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
3864b5e93edSEtienne Carriere {
387077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
3884b5e93edSEtienne Carriere 
389077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
390077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
391077d486eSEtienne Carriere 			return bank;
392077d486eSEtienne Carriere 
393077d486eSEtienne Carriere 	panic();
394077d486eSEtienne Carriere }
395077d486eSEtienne Carriere 
396077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
397bfc43b68SGatien Chevallier static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
398077d486eSEtienne Carriere {
399077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
400077d486eSEtienne Carriere 
401077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
402077d486eSEtienne Carriere 		panic();
4034b5e93edSEtienne Carriere 
4044b5e93edSEtienne Carriere 	/*
4054b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
4064b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
4074b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
4084b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
4094b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
4104b5e93edSEtienne Carriere 	 */
411077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
4124b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
4134b5e93edSEtienne Carriere 
414077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
4154b5e93edSEtienne Carriere 
416077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
417077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
4184b5e93edSEtienne Carriere 
419077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
4204b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
4214b5e93edSEtienne Carriere 
422077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
4234b5e93edSEtienne Carriere 
4244b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
425077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
426077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
4274b5e93edSEtienne Carriere 	else
428077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
4294b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
4304b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
4314b5e93edSEtienne Carriere 
432077d486eSEtienne Carriere 	clk_disable(bank->clock);
4334b5e93edSEtienne Carriere }
4344b5e93edSEtienne Carriere 
4354b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
436077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
4374b5e93edSEtienne Carriere {
438077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
43998dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
4404b5e93edSEtienne Carriere 
441077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
442077d486eSEtienne Carriere 		panic();
44398dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
4444b5e93edSEtienne Carriere 
4454b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
446077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
447bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
448bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
4494b5e93edSEtienne Carriere 
4504b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
451077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
452bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
4534b5e93edSEtienne Carriere 
4544b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
455077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
456bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
457bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
4584b5e93edSEtienne Carriere 
4594b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
460077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
461bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
4624b5e93edSEtienne Carriere 
4634b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
4644b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
465077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
466bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
467bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
4684b5e93edSEtienne Carriere 	} else {
4694b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
4704b5e93edSEtienne Carriere 
471077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
472bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
473bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
4744b5e93edSEtienne Carriere 	}
4754b5e93edSEtienne Carriere 
4764b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
477077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
4784b5e93edSEtienne Carriere 
479c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
48098dfcedaSEtienne Carriere 	clk_disable(bank->clock);
4814b5e93edSEtienne Carriere }
4824b5e93edSEtienne Carriere 
4834b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
484b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
4854b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
4864b5e93edSEtienne Carriere {
487b38386fbSEtienne Carriere 	const fdt32_t *cuint = NULL;
488b38386fbSEtienne Carriere 	const fdt32_t *slewrate = NULL;
48910bcbd6cSEtienne Carriere 	int len = 0;
49010bcbd6cSEtienne Carriere 	uint32_t i = 0;
4914b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
4924b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
4934b5e93edSEtienne Carriere 	size_t found = 0;
4944b5e93edSEtienne Carriere 
4954b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
4964b5e93edSEtienne Carriere 	if (!cuint)
4974b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
4984b5e93edSEtienne Carriere 
4994b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
5004b5e93edSEtienne Carriere 	if (slewrate)
5014b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
5024b5e93edSEtienne Carriere 
5034b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
5044b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
5054b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
5064b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
5074b5e93edSEtienne Carriere 
5084b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
50910bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
51010bcbd6cSEtienne Carriere 		uint32_t bank = 0;
51110bcbd6cSEtienne Carriere 		uint32_t pin = 0;
51210bcbd6cSEtienne Carriere 		uint32_t mode = 0;
5134b5e93edSEtienne Carriere 		uint32_t alternate = 0;
514322cf9e3SEtienne Carriere 		uint32_t odata = 0;
5154b5e93edSEtienne Carriere 		bool opendrain = false;
5164b5e93edSEtienne Carriere 
5174b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
5184b5e93edSEtienne Carriere 		cuint++;
5194b5e93edSEtienne Carriere 
5204b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
5214b5e93edSEtienne Carriere 
5224b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
5234b5e93edSEtienne Carriere 
5244b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
5254b5e93edSEtienne Carriere 
5264b5e93edSEtienne Carriere 		switch (mode) {
5274b5e93edSEtienne Carriere 		case 0:
5284b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
5294b5e93edSEtienne Carriere 			break;
5304b5e93edSEtienne Carriere 		case 1:
5314b5e93edSEtienne Carriere 		case 2:
5324b5e93edSEtienne Carriere 		case 3:
5334b5e93edSEtienne Carriere 		case 4:
5344b5e93edSEtienne Carriere 		case 5:
5354b5e93edSEtienne Carriere 		case 6:
5364b5e93edSEtienne Carriere 		case 7:
5374b5e93edSEtienne Carriere 		case 8:
5384b5e93edSEtienne Carriere 		case 9:
5394b5e93edSEtienne Carriere 		case 10:
5404b5e93edSEtienne Carriere 		case 11:
5414b5e93edSEtienne Carriere 		case 12:
5424b5e93edSEtienne Carriere 		case 13:
5434b5e93edSEtienne Carriere 		case 14:
5444b5e93edSEtienne Carriere 		case 15:
5454b5e93edSEtienne Carriere 		case 16:
5464b5e93edSEtienne Carriere 			alternate = mode - 1U;
5474b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
5484b5e93edSEtienne Carriere 			break;
5494b5e93edSEtienne Carriere 		case 17:
5504b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
5514b5e93edSEtienne Carriere 			break;
5524b5e93edSEtienne Carriere 		default:
5534b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
5544b5e93edSEtienne Carriere 			break;
5554b5e93edSEtienne Carriere 		}
5564b5e93edSEtienne Carriere 
5574b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
5584b5e93edSEtienne Carriere 			opendrain = true;
5594b5e93edSEtienne Carriere 
560322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-high", NULL) &&
561322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
562322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
563322cf9e3SEtienne Carriere 			odata = 1;
564322cf9e3SEtienne Carriere 		}
565322cf9e3SEtienne Carriere 
566322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-low", NULL) &&
567322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
568322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
569322cf9e3SEtienne Carriere 			odata = 0;
570322cf9e3SEtienne Carriere 		}
571322cf9e3SEtienne Carriere 
5724b5e93edSEtienne Carriere 		if (found < count) {
5734b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
5744b5e93edSEtienne Carriere 
5754b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
5764b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
577b38386fbSEtienne Carriere 			ref->cfg.mode = mode;
578b38386fbSEtienne Carriere 			if (opendrain)
579b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
580b38386fbSEtienne Carriere 			else
581b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
582b38386fbSEtienne Carriere 			ref->cfg.ospeed = speed;
583b38386fbSEtienne Carriere 			ref->cfg.pupd = pull;
584b38386fbSEtienne Carriere 			ref->cfg.od = odata;
585b38386fbSEtienne Carriere 			ref->cfg.af = alternate;
5864b5e93edSEtienne Carriere 		}
5874b5e93edSEtienne Carriere 
5884b5e93edSEtienne Carriere 		found++;
5894b5e93edSEtienne Carriere 	}
5904b5e93edSEtienne Carriere 
5914b5e93edSEtienne Carriere 	return (int)found;
5924b5e93edSEtienne Carriere }
5934b5e93edSEtienne Carriere 
594bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op,
595bfc43b68SGatien Chevallier 				    unsigned int pm_hint __unused,
596bfc43b68SGatien Chevallier 				    const struct pm_callback_handle *pm_hdl)
597bfc43b68SGatien Chevallier {
598bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *handle = pm_hdl->handle;
599bfc43b68SGatien Chevallier 	unsigned int bank_id = handle->gpio_pinctrl.bank;
600bfc43b68SGatien Chevallier 	unsigned int pin = handle->gpio_pinctrl.pin;
601bfc43b68SGatien Chevallier 	struct gpio_chip *chip = &stm32_gpio_get_bank(bank_id)->gpio_chip;
602bfc43b68SGatien Chevallier 
603bfc43b68SGatien Chevallier 	if (op == PM_OP_RESUME) {
604bfc43b68SGatien Chevallier 		set_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
605bfc43b68SGatien Chevallier 		if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
606bfc43b68SGatien Chevallier 			stm32_gpio_set_level(chip, pin, handle->level);
607bfc43b68SGatien Chevallier 	} else {
608bfc43b68SGatien Chevallier 		get_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
609bfc43b68SGatien Chevallier 		if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
610bfc43b68SGatien Chevallier 			handle->level = stm32_gpio_get_level(chip, pin);
611bfc43b68SGatien Chevallier 	}
612bfc43b68SGatien Chevallier 
613bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
614bfc43b68SGatien Chevallier }
615bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(consumed_gpios_pm);
616bfc43b68SGatien Chevallier 
617b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
618b357d34fSEtienne Carriere 				    struct gpio **out_gpio)
619420a32c5SEtienne Carriere {
620b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
6217761b658SEtienne Carriere 	struct stm32_gpio_pm_state *reg_state = NULL;
622bfc43b68SGatien Chevallier 	struct stm32_gpio_pm_state *state = NULL;
623420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
624420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
625420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
626420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
627420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
628420a32c5SEtienne Carriere 	uint32_t otype = 0;
629420a32c5SEtienne Carriere 	uint32_t pupd = 0;
630420a32c5SEtienne Carriere 	uint32_t mode = 0;
631420a32c5SEtienne Carriere 
632b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
633b357d34fSEtienne Carriere 	if (res)
634b357d34fSEtienne Carriere 		return res;
635420a32c5SEtienne Carriere 
636420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
637420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
638420a32c5SEtienne Carriere 		free(gpio);
639b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
640420a32c5SEtienne Carriere 	}
641420a32c5SEtienne Carriere 
642bfc43b68SGatien Chevallier 	state = calloc(1, sizeof(*state));
643bfc43b68SGatien Chevallier 	if (!state) {
644bfc43b68SGatien Chevallier 		free(gpio);
645bfc43b68SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
646bfc43b68SGatien Chevallier 	}
647bfc43b68SGatien Chevallier 
6487761b658SEtienne Carriere 	SLIST_FOREACH(reg_state, &consumed_gpios_head, link) {
6497761b658SEtienne Carriere 		if (reg_state->gpio_pinctrl.bank == bank->bank_id &&
6507761b658SEtienne Carriere 		    reg_state->gpio_pinctrl.pin == gpio->pin) {
6517761b658SEtienne Carriere 			EMSG("node %s: GPIO %c%u is used by another device",
6527761b658SEtienne Carriere 			     fdt_get_name(pargs->fdt, pargs->consumer_node,
6537761b658SEtienne Carriere 					  NULL),
6547761b658SEtienne Carriere 			     bank->bank_id + 'A', gpio->pin);
6557761b658SEtienne Carriere 			free(state);
6567761b658SEtienne Carriere 			free(gpio);
6577761b658SEtienne Carriere 			return TEE_ERROR_GENERIC;
6587761b658SEtienne Carriere 		}
6597761b658SEtienne Carriere 	}
6607761b658SEtienne Carriere 
661bfc43b68SGatien Chevallier 	state->gpio_pinctrl.pin = gpio->pin;
662bfc43b68SGatien Chevallier 	state->gpio_pinctrl.bank = bank->bank_id;
663bfc43b68SGatien Chevallier 	SLIST_INSERT_HEAD(&consumed_gpios_head, state, link);
664bfc43b68SGatien Chevallier 
665bfc43b68SGatien Chevallier 	register_pm_driver_cb(consumed_gpios_pm, state, "stm32-gpio-state");
666bfc43b68SGatien Chevallier 
667420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
668420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
669420a32c5SEtienne Carriere 
670420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
671420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
672420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
673420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
674420a32c5SEtienne Carriere 	else
675420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
676420a32c5SEtienne Carriere 
677420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
678420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
679420a32c5SEtienne Carriere 	else
680420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
681420a32c5SEtienne Carriere 
682420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
683420a32c5SEtienne Carriere 		panic();
684420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
685420a32c5SEtienne Carriere 
686420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
687420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
688420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
689420a32c5SEtienne Carriere 
690420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
691420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
692420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
693420a32c5SEtienne Carriere 
694420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
695420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
696420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
697420a32c5SEtienne Carriere 
698420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
699420a32c5SEtienne Carriere 	clk_disable(bank->clock);
700420a32c5SEtienne Carriere 
701420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
702420a32c5SEtienne Carriere 
703b357d34fSEtienne Carriere 	*out_gpio = gpio;
704420a32c5SEtienne Carriere 
705b357d34fSEtienne Carriere 	return TEE_SUCCESS;
706420a32c5SEtienne Carriere }
707420a32c5SEtienne Carriere 
7089818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
7099818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
7109818a481SEtienne Carriere {
7119818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
7129818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
7139818a481SEtienne Carriere 	int len = 0;
7149818a481SEtienne Carriere 
7159818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
7169818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
7179818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
7189818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
7199818a481SEtienne Carriere 
7209818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
7219818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
7229818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
7239818a481SEtienne Carriere 
7249818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
7259818a481SEtienne Carriere }
7269818a481SEtienne Carriere 
7279818a481SEtienne Carriere /*
7289818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
7299818a481SEtienne Carriere  * registered in the GPIO bank link.
7309818a481SEtienne Carriere  */
7319818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
7329818a481SEtienne Carriere {
7339818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
7349818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
7359818a481SEtienne Carriere 
7369818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
7379818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
7389818a481SEtienne Carriere 			return true;
7399818a481SEtienne Carriere 
7409818a481SEtienne Carriere 	return false;
7419818a481SEtienne Carriere }
7429818a481SEtienne Carriere 
7439def1fb7SGatien Chevallier #ifdef CFG_STM32_RIF
744*a72f07daSEtienne Carriere static TEE_Result handle_available_semaphores(struct stm32_gpio_bank *bank,
745*a72f07daSEtienne Carriere 					      uint32_t gpios_mask)
746bd03c8c3SGatien Chevallier {
747bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
748bd03c8c3SGatien Chevallier 	uint32_t cidcfgr = 0;
749bd03c8c3SGatien Chevallier 	unsigned int i = 0;
750bd03c8c3SGatien Chevallier 
7519def1fb7SGatien Chevallier 	for (i = 0 ; i < bank->ngpios; i++) {
752*a72f07daSEtienne Carriere 		if (!(BIT(i) & gpios_mask))
7539def1fb7SGatien Chevallier 			continue;
7549def1fb7SGatien Chevallier 
7559def1fb7SGatien Chevallier 		cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i));
7569def1fb7SGatien Chevallier 
7579def1fb7SGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
7589def1fb7SGatien Chevallier 			continue;
7599def1fb7SGatien Chevallier 
7609def1fb7SGatien Chevallier 		if (!(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) {
7619def1fb7SGatien Chevallier 			res = stm32_rif_release_semaphore(bank->base +
7629def1fb7SGatien Chevallier 							  GPIO_SEMCR(i),
7639def1fb7SGatien Chevallier 							  MAX_CID_SUPPORTED);
7649def1fb7SGatien Chevallier 			if (res) {
7659def1fb7SGatien Chevallier 				EMSG("Cannot release semaphore for resource %u",
7669def1fb7SGatien Chevallier 				     i);
7679def1fb7SGatien Chevallier 				return res;
7689def1fb7SGatien Chevallier 			}
7699def1fb7SGatien Chevallier 		} else {
7709def1fb7SGatien Chevallier 			res = stm32_rif_acquire_semaphore(bank->base +
7719def1fb7SGatien Chevallier 							  GPIO_SEMCR(i),
7729def1fb7SGatien Chevallier 							  MAX_CID_SUPPORTED);
7739def1fb7SGatien Chevallier 			if (res) {
7749def1fb7SGatien Chevallier 				EMSG("Cannot acquire semaphore for resource %u",
7759def1fb7SGatien Chevallier 				     i);
7769def1fb7SGatien Chevallier 				return res;
7779def1fb7SGatien Chevallier 			}
7789def1fb7SGatien Chevallier 		}
7799def1fb7SGatien Chevallier 	}
7809def1fb7SGatien Chevallier 
7819def1fb7SGatien Chevallier 	return TEE_SUCCESS;
7829def1fb7SGatien Chevallier }
7839def1fb7SGatien Chevallier 
784*a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank,
785*a72f07daSEtienne Carriere 				   uint32_t gpios_mask)
7869def1fb7SGatien Chevallier {
7879def1fb7SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
7889def1fb7SGatien Chevallier 	unsigned int i = 0;
7899def1fb7SGatien Chevallier 
790bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
791bd03c8c3SGatien Chevallier 		return TEE_SUCCESS;
792bd03c8c3SGatien Chevallier 
793bd03c8c3SGatien Chevallier 	if (clk_enable(bank->clock))
794bd03c8c3SGatien Chevallier 		panic();
795bd03c8c3SGatien Chevallier 
7969def1fb7SGatien Chevallier 	if (bank->is_tdcid) {
797bd03c8c3SGatien Chevallier 		for (i = 0; i < bank->ngpios; i++) {
798*a72f07daSEtienne Carriere 			if (!(BIT(i) & gpios_mask))
799bd03c8c3SGatien Chevallier 				continue;
800bd03c8c3SGatien Chevallier 
801bd03c8c3SGatien Chevallier 			/*
8029def1fb7SGatien Chevallier 			 * When TDCID, OP-TEE should be the one to set the CID
8039def1fb7SGatien Chevallier 			 * filtering configuration. Clearing previous
8049def1fb7SGatien Chevallier 			 * configuration prevents undesired events during the
8059def1fb7SGatien Chevallier 			 * only legitimate configuration.
806bd03c8c3SGatien Chevallier 			 */
807bd03c8c3SGatien Chevallier 			io_clrbits32(bank->base + GPIO_CIDCFGR(i),
808bd03c8c3SGatien Chevallier 				     GPIO_CIDCFGR_CONF_MASK);
809bd03c8c3SGatien Chevallier 		}
8109def1fb7SGatien Chevallier 	} else {
811*a72f07daSEtienne Carriere 		res = handle_available_semaphores(bank, gpios_mask);
8129def1fb7SGatien Chevallier 		if (res)
8139def1fb7SGatien Chevallier 			panic();
814bd03c8c3SGatien Chevallier 	}
815bd03c8c3SGatien Chevallier 
816bd03c8c3SGatien Chevallier 	/* Security and privilege RIF configuration */
817*a72f07daSEtienne Carriere 	io_mask32(bank->base + GPIO_PRIVCFGR_OFFSET,
818*a72f07daSEtienne Carriere 		  bank->rif_cfg->priv_conf[0], gpios_mask);
819*a72f07daSEtienne Carriere 	io_mask32(bank->base + GPIO_SECR_OFFSET,
820*a72f07daSEtienne Carriere 		  bank->rif_cfg->sec_conf[0], gpios_mask);
821bd03c8c3SGatien Chevallier 
822bd03c8c3SGatien Chevallier 	if (!bank->is_tdcid) {
823bd03c8c3SGatien Chevallier 		res = TEE_SUCCESS;
824bd03c8c3SGatien Chevallier 		goto out;
825bd03c8c3SGatien Chevallier 	}
826bd03c8c3SGatien Chevallier 
827bd03c8c3SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++) {
828*a72f07daSEtienne Carriere 		if (!(BIT(i) & gpios_mask))
829bd03c8c3SGatien Chevallier 			continue;
830bd03c8c3SGatien Chevallier 
831bd03c8c3SGatien Chevallier 		io_clrsetbits32(bank->base + GPIO_CIDCFGR(i),
832bd03c8c3SGatien Chevallier 				GPIO_CIDCFGR_CONF_MASK,
833bd03c8c3SGatien Chevallier 				bank->rif_cfg->cid_confs[i]);
834bd03c8c3SGatien Chevallier 	}
835bd03c8c3SGatien Chevallier 
836bd03c8c3SGatien Chevallier 	/*
837bd03c8c3SGatien Chevallier 	 * Lock RIF configuration if configured. This cannot be undone until
838bd03c8c3SGatien Chevallier 	 * next reset.
839bd03c8c3SGatien Chevallier 	 */
840bd03c8c3SGatien Chevallier 	io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET,
841bd03c8c3SGatien Chevallier 		     bank->rif_cfg->lock_conf[0]);
842bd03c8c3SGatien Chevallier 
843*a72f07daSEtienne Carriere 	res = handle_available_semaphores(bank, gpios_mask);
8449def1fb7SGatien Chevallier 	if (res)
8459def1fb7SGatien Chevallier 		panic();
8469def1fb7SGatien Chevallier 
8479def1fb7SGatien Chevallier out:
848bd03c8c3SGatien Chevallier 	if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) {
849bd03c8c3SGatien Chevallier 		/* Check that RIF config are applied, panic otherwise */
850bd03c8c3SGatien Chevallier 		if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) &
851*a72f07daSEtienne Carriere 		     gpios_mask) !=
852*a72f07daSEtienne Carriere 		    (bank->rif_cfg->priv_conf[0] & gpios_mask)) {
853bd03c8c3SGatien Chevallier 			EMSG("GPIO bank%c priv conf is incorrect",
854bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
855bd03c8c3SGatien Chevallier 			panic();
856bd03c8c3SGatien Chevallier 		}
857bd03c8c3SGatien Chevallier 
858*a72f07daSEtienne Carriere 		if ((io_read32(bank->base + GPIO_SECR_OFFSET) & gpios_mask) !=
859*a72f07daSEtienne Carriere 		    (bank->rif_cfg->sec_conf[0] & gpios_mask)) {
860bd03c8c3SGatien Chevallier 			EMSG("GPIO bank %c sec conf is incorrect",
861bd03c8c3SGatien Chevallier 			     'A' + bank->bank_id);
862bd03c8c3SGatien Chevallier 			panic();
863bd03c8c3SGatien Chevallier 		}
864bd03c8c3SGatien Chevallier 	}
865bd03c8c3SGatien Chevallier 
866bd03c8c3SGatien Chevallier 	clk_disable(bank->clock);
867bd03c8c3SGatien Chevallier 
868bd03c8c3SGatien Chevallier 	return res;
869bd03c8c3SGatien Chevallier }
8709def1fb7SGatien Chevallier #else /* CFG_STM32_RIF */
871*a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank __unused,
872*a72f07daSEtienne Carriere 				   uint32_t gpios_mask __unused)
8739def1fb7SGatien Chevallier {
8749def1fb7SGatien Chevallier 	return TEE_SUCCESS;
8759def1fb7SGatien Chevallier }
8769def1fb7SGatien Chevallier #endif /* CFG_STM32_RIF */
877bd03c8c3SGatien Chevallier 
878bfc43b68SGatien Chevallier static void stm32_gpio_save_rif_config(struct stm32_gpio_bank *bank)
879bfc43b68SGatien Chevallier {
880bfc43b68SGatien Chevallier 	size_t i = 0;
881bfc43b68SGatien Chevallier 
882bfc43b68SGatien Chevallier 	for (i = 0; i < bank->ngpios; i++)
883bfc43b68SGatien Chevallier 		bank->rif_cfg->cid_confs[i] = io_read32(bank->base +
884bfc43b68SGatien Chevallier 							 GPIO_CIDCFGR(i));
885bfc43b68SGatien Chevallier 
886bfc43b68SGatien Chevallier 	bank->rif_cfg->priv_conf[0] = io_read32(bank->base +
887bfc43b68SGatien Chevallier 						GPIO_PRIVCFGR_OFFSET);
888bfc43b68SGatien Chevallier 	bank->rif_cfg->sec_conf[0] = io_read32(bank->base +
889bfc43b68SGatien Chevallier 					       GPIO_SECR_OFFSET);
890bfc43b68SGatien Chevallier 	bank->rif_cfg->lock_conf[0] = io_read32(bank->base +
891bfc43b68SGatien Chevallier 						GPIO_RCFGLOCKR_OFFSET);
892bfc43b68SGatien Chevallier }
893bfc43b68SGatien Chevallier 
894bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank,
895bd03c8c3SGatien Chevallier 				      const void *fdt, int node)
896bd03c8c3SGatien Chevallier {
897bd03c8c3SGatien Chevallier 	unsigned int i = 0;
898bd03c8c3SGatien Chevallier 	unsigned int nb_rif_conf = 0;
899bd03c8c3SGatien Chevallier 	int lenp = 0;
900bd03c8c3SGatien Chevallier 	const fdt32_t *cuint = NULL;
901bd03c8c3SGatien Chevallier 
902bd03c8c3SGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
903bd03c8c3SGatien Chevallier 	if (!cuint) {
904bd03c8c3SGatien Chevallier 		DMSG("No RIF configuration available");
905bd03c8c3SGatien Chevallier 		return;
906bd03c8c3SGatien Chevallier 	}
907bd03c8c3SGatien Chevallier 
908bd03c8c3SGatien Chevallier 	bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg));
909bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg)
910bd03c8c3SGatien Chevallier 		panic();
911bd03c8c3SGatien Chevallier 
912bd03c8c3SGatien Chevallier 	bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t));
913bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->sec_conf)
914bd03c8c3SGatien Chevallier 		panic();
915bd03c8c3SGatien Chevallier 
916bd03c8c3SGatien Chevallier 	nb_rif_conf = (unsigned int)(lenp / sizeof(uint32_t));
917bd03c8c3SGatien Chevallier 	assert(nb_rif_conf <= bank->ngpios);
918bd03c8c3SGatien Chevallier 
919bd03c8c3SGatien Chevallier 	bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t));
920bd03c8c3SGatien Chevallier 	bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t));
921bd03c8c3SGatien Chevallier 	bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t));
922bd03c8c3SGatien Chevallier 	bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t));
923bd03c8c3SGatien Chevallier 	if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask ||
924bd03c8c3SGatien Chevallier 	    !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf)
925bd03c8c3SGatien Chevallier 		panic("Missing memory capacity for GPIOS RIF configuration");
926bd03c8c3SGatien Chevallier 
927bd03c8c3SGatien Chevallier 	for (i = 0; i < nb_rif_conf; i++)
928bd03c8c3SGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg,
929646ad62bSGatien Chevallier 				    bank->ngpios);
930bd03c8c3SGatien Chevallier }
931bd03c8c3SGatien Chevallier 
9329818a481SEtienne Carriere /* Get GPIO bank information from the DT */
9339818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
934e569f6adSEtienne Carriere 				     const void *compat_data,
9359818a481SEtienne Carriere 				     int range_offset,
9369818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
9379818a481SEtienne Carriere {
938e569f6adSEtienne Carriere 	const struct bank_compat *compat = compat_data;
9399818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
9409818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
9419818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
9429818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
9439818a481SEtienne Carriere 	struct clk *clk = NULL;
9449818a481SEtienne Carriere 	size_t blen = 0;
9459818a481SEtienne Carriere 	paddr_t pa = 0;
9469818a481SEtienne Carriere 	int len = 0;
9479818a481SEtienne Carriere 	int i = 0;
9489818a481SEtienne Carriere 
9499818a481SEtienne Carriere 	assert(out_bank);
9509818a481SEtienne Carriere 
9519818a481SEtienne Carriere 	/* Probe deferrable devices first */
9529818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
9539818a481SEtienne Carriere 	if (res)
9549818a481SEtienne Carriere 		return res;
9559818a481SEtienne Carriere 
9569818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
9579818a481SEtienne Carriere 	if (!bank)
9589818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
9599818a481SEtienne Carriere 
960bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
961bd03c8c3SGatien Chevallier 		res = stm32_rifsc_check_tdcid(&bank->is_tdcid);
962bd03c8c3SGatien Chevallier 		if (res) {
963bd03c8c3SGatien Chevallier 			free(bank);
964bd03c8c3SGatien Chevallier 			return res;
965bd03c8c3SGatien Chevallier 		}
966bd03c8c3SGatien Chevallier 	}
967bd03c8c3SGatien Chevallier 
9689818a481SEtienne Carriere 	/*
9699818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
9709818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
9719818a481SEtienne Carriere 	 */
9726a0116edSEtienne Carriere 	if (fdt_reg_info(fdt, node, &pa, &blen))
9736a0116edSEtienne Carriere 		panic("missing reg or reg size property");
9749818a481SEtienne Carriere 
9759818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
9769818a481SEtienne Carriere 
9779818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
9789818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
9799818a481SEtienne Carriere 	bank->clock = clk;
980420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
981b4893304SGatien Chevallier 	bank->sec_support = compat->secure_control;
9829818a481SEtienne Carriere 
9839818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
9849818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
9859818a481SEtienne Carriere 	len /= sizeof(*cuint);
9869818a481SEtienne Carriere 	if (len % 4)
9879818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
9889818a481SEtienne Carriere 
9899818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
9909818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
9919818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
9929818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
9939818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
9949818a481SEtienne Carriere 		cuint += 4;
9959818a481SEtienne Carriere 	}
9969818a481SEtienne Carriere 
997bd03c8c3SGatien Chevallier 	if (compat->secure_extended) {
998bd03c8c3SGatien Chevallier 		/* RIF configuration */
999bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
1000bd03c8c3SGatien Chevallier 
1001bd03c8c3SGatien Chevallier 		stm32_parse_gpio_rif_conf(bank, fdt, node);
1002bd03c8c3SGatien Chevallier 	} else if (bank->sec_support) {
1003bd03c8c3SGatien Chevallier 		/* Secure configuration */
1004bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
1005bd03c8c3SGatien Chevallier 		cuint = fdt_getprop(fdt, node, "st,protreg", NULL);
1006bd03c8c3SGatien Chevallier 		if (cuint)
1007bd03c8c3SGatien Chevallier 			bank->seccfgr = fdt32_to_cpu(*cuint);
1008bd03c8c3SGatien Chevallier 		else
1009bd03c8c3SGatien Chevallier 			DMSG("GPIO bank %c assigned to non-secure",
1010bd03c8c3SGatien Chevallier 			     bank->bank_id + 'A');
1011bd03c8c3SGatien Chevallier 	} else {
1012bd03c8c3SGatien Chevallier 		bank->base = io_pa_or_va_nsec(&pa_va, blen);
1013bd03c8c3SGatien Chevallier 	}
1014bd03c8c3SGatien Chevallier 
1015e569f6adSEtienne Carriere 	if (compat->gpioz)
1016e569f6adSEtienne Carriere 		stm32mp_register_gpioz_pin_count(bank->ngpios);
1017e569f6adSEtienne Carriere 
10189818a481SEtienne Carriere 	*out_bank = bank;
1019bd03c8c3SGatien Chevallier 
10209818a481SEtienne Carriere 	return TEE_SUCCESS;
10219818a481SEtienne Carriere }
10229818a481SEtienne Carriere 
1023bd03c8c3SGatien Chevallier /* Parse a pinctrl node to register the GPIO banks it describes */
10240e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
10259818a481SEtienne Carriere 					const void *compat_data)
10269818a481SEtienne Carriere {
10279818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
10289818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
10299818a481SEtienne Carriere 	int range_offs = 0;
10309818a481SEtienne Carriere 	int b_node = 0;
10319818a481SEtienne Carriere 	int len = 0;
10329818a481SEtienne Carriere 
10339818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
10349818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
10359818a481SEtienne Carriere 	if (!cuint)
10369818a481SEtienne Carriere 		panic("missing ranges property");
10379818a481SEtienne Carriere 
10389818a481SEtienne Carriere 	len /= sizeof(*cuint);
10399818a481SEtienne Carriere 	if (len == 3)
10409818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
10419818a481SEtienne Carriere 
10429818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
10439818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
10449818a481SEtienne Carriere 		if (cuint) {
10459818a481SEtienne Carriere 			/*
10469818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
10479818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
10489818a481SEtienne Carriere 			 * bank list.
10499818a481SEtienne Carriere 			 */
10509818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
10519818a481SEtienne Carriere 
10529818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
10539818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
10549818a481SEtienne Carriere 				continue;
10559818a481SEtienne Carriere 
10569818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
10579818a481SEtienne Carriere 						 range_offs, &bank);
10589818a481SEtienne Carriere 			if (res)
10599818a481SEtienne Carriere 				return res;
10609818a481SEtienne Carriere 
1061420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
1062420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
1063420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
1064420a32c5SEtienne Carriere 			if (res)
1065420a32c5SEtienne Carriere 				panic();
1066420a32c5SEtienne Carriere 
10679818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
10689818a481SEtienne Carriere 		} else {
10699818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
10709818a481SEtienne Carriere 				panic();
10719818a481SEtienne Carriere 		}
10729818a481SEtienne Carriere 	}
10739818a481SEtienne Carriere 
10749818a481SEtienne Carriere 	return TEE_SUCCESS;
10759818a481SEtienne Carriere }
10769818a481SEtienne Carriere 
1077077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
1078077d486eSEtienne Carriere 			       bool secure)
10794b5e93edSEtienne Carriere {
1080077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
108198dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
10824b5e93edSEtienne Carriere 
1083077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
1084077d486eSEtienne Carriere 		panic();
108598dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
10864b5e93edSEtienne Carriere 
10874b5e93edSEtienne Carriere 	if (secure)
1088077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
10894b5e93edSEtienne Carriere 	else
1090077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
10914b5e93edSEtienne Carriere 
1092c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
109398dfcedaSEtienne Carriere 	clk_disable(bank->clock);
10944b5e93edSEtienne Carriere }
10950e0435e2SEtienne Carriere 
1096b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1097b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
1098b38386fbSEtienne Carriere {
1099b38386fbSEtienne Carriere 	struct stm32_pinctrl_array *ref = conf->priv;
1100b38386fbSEtienne Carriere 	struct stm32_pinctrl *p = ref->pinctrl;
1101b38386fbSEtienne Carriere 	size_t pin_count = ref->count;
1102b38386fbSEtienne Carriere 	size_t n = 0;
1103b38386fbSEtienne Carriere 
1104b38386fbSEtienne Carriere 	for (n = 0; n < pin_count; n++)
1105b38386fbSEtienne Carriere 		set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
1106b38386fbSEtienne Carriere 
1107b38386fbSEtienne Carriere 	return TEE_SUCCESS;
1108b38386fbSEtienne Carriere }
1109b38386fbSEtienne Carriere 
1110b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
1111b38386fbSEtienne Carriere {
1112b38386fbSEtienne Carriere 	free(conf);
1113b38386fbSEtienne Carriere }
1114b38386fbSEtienne Carriere 
1115b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
1116b38386fbSEtienne Carriere 	.conf_apply = stm32_pinctrl_conf_apply,
1117b38386fbSEtienne Carriere 	.conf_free = stm32_pinctrl_conf_free,
1118b38386fbSEtienne Carriere };
1119b38386fbSEtienne Carriere 
1120b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
1121b38386fbSEtienne Carriere 
112270ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
112370ac0db5SEtienne Carriere 				 unsigned int *bank, unsigned int *pin,
112470ac0db5SEtienne Carriere 				 unsigned int *count)
112570ac0db5SEtienne Carriere {
112670ac0db5SEtienne Carriere 	size_t conf_index = 0;
112770ac0db5SEtienne Carriere 	size_t pin_count = 0;
112870ac0db5SEtienne Carriere 	size_t n = 0;
112970ac0db5SEtienne Carriere 
113070ac0db5SEtienne Carriere 	assert(count);
113170ac0db5SEtienne Carriere 	if (!pinctrl)
113270ac0db5SEtienne Carriere 		goto out;
113370ac0db5SEtienne Carriere 
113470ac0db5SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
113570ac0db5SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
113670ac0db5SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
113770ac0db5SEtienne Carriere 
113870ac0db5SEtienne Carriere 		/* Consider only the stm32_gpio pins */
113970ac0db5SEtienne Carriere 		if (pinconf->ops != &stm32_pinctrl_ops)
114070ac0db5SEtienne Carriere 			continue;
114170ac0db5SEtienne Carriere 
114270ac0db5SEtienne Carriere 		if (bank || pin) {
114370ac0db5SEtienne Carriere 			for (n = 0; n < ref->count; n++) {
114470ac0db5SEtienne Carriere 				if (bank && pin_count < *count)
114570ac0db5SEtienne Carriere 					bank[pin_count] = ref->pinctrl[n].bank;
114670ac0db5SEtienne Carriere 				if (pin && pin_count < *count)
114770ac0db5SEtienne Carriere 					pin[pin_count] = ref->pinctrl[n].pin;
114870ac0db5SEtienne Carriere 				pin_count++;
114970ac0db5SEtienne Carriere 			}
115070ac0db5SEtienne Carriere 		} else {
115170ac0db5SEtienne Carriere 			pin_count += ref->count;
115270ac0db5SEtienne Carriere 		}
115370ac0db5SEtienne Carriere 	}
115470ac0db5SEtienne Carriere 
115570ac0db5SEtienne Carriere out:
115670ac0db5SEtienne Carriere 	*count = pin_count;
115770ac0db5SEtienne Carriere }
115870ac0db5SEtienne Carriere 
11597f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure)
11607f823a77SEtienne Carriere {
11617f823a77SEtienne Carriere 	size_t conf_index = 0;
11627f823a77SEtienne Carriere 
11637f823a77SEtienne Carriere 	if (!pinctrl)
11647f823a77SEtienne Carriere 		return;
11657f823a77SEtienne Carriere 
11667f823a77SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
11677f823a77SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
11687f823a77SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
11697f823a77SEtienne Carriere 		struct stm32_pinctrl *pc = NULL;
11707f823a77SEtienne Carriere 		size_t n = 0;
11717f823a77SEtienne Carriere 
11727f823a77SEtienne Carriere 		for (n = 0; n < ref->count; n++) {
11737f823a77SEtienne Carriere 			if (pinconf->ops != &stm32_pinctrl_ops)
11747f823a77SEtienne Carriere 				continue;
11757f823a77SEtienne Carriere 
11767f823a77SEtienne Carriere 			pc = ref->pinctrl + n;
11777f823a77SEtienne Carriere 			stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure);
11787f823a77SEtienne Carriere 		}
11797f823a77SEtienne Carriere 	}
11807f823a77SEtienne Carriere }
11817f823a77SEtienne Carriere 
1182b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
1183b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
1184b38386fbSEtienne Carriere 				       void *data __unused,
1185b38386fbSEtienne Carriere 				       struct pinconf **out_pinconf)
1186b38386fbSEtienne Carriere {
1187b38386fbSEtienne Carriere 	struct conf {
1188b38386fbSEtienne Carriere 		struct pinconf pinconf;
1189b38386fbSEtienne Carriere 		struct stm32_pinctrl_array array_ref;
1190b38386fbSEtienne Carriere 	} *loc_conf = NULL;
1191b38386fbSEtienne Carriere 	struct stm32_pinctrl *pinctrl = NULL;
1192b38386fbSEtienne Carriere 	struct pinconf *pinconf = NULL;
1193b38386fbSEtienne Carriere 	const void *fdt = NULL;
1194b38386fbSEtienne Carriere 	size_t pin_count = 0;
1195b38386fbSEtienne Carriere 	int pinctrl_node = 0;
1196b38386fbSEtienne Carriere 	int pinmux_node = 0;
1197b38386fbSEtienne Carriere 	int count = 0;
1198b38386fbSEtienne Carriere 
1199b38386fbSEtienne Carriere 	pinctrl_node = pargs->phandle_node;
1200b38386fbSEtienne Carriere 	fdt = pargs->fdt;
1201b38386fbSEtienne Carriere 	assert(fdt && pinctrl_node);
1202b38386fbSEtienne Carriere 
1203b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1204b38386fbSEtienne Carriere 		if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
1205b38386fbSEtienne Carriere 			pin_count += (size_t)count / sizeof(uint32_t);
1206b38386fbSEtienne Carriere 		else if (count != -FDT_ERR_NOTFOUND)
1207b38386fbSEtienne Carriere 			panic();
1208b38386fbSEtienne Carriere 	}
1209b38386fbSEtienne Carriere 
1210b38386fbSEtienne Carriere 	loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
1211b38386fbSEtienne Carriere 	if (!loc_conf)
1212b38386fbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
1213b38386fbSEtienne Carriere 
1214b38386fbSEtienne Carriere 	pinconf = &loc_conf->pinconf;
1215b38386fbSEtienne Carriere 	pinconf->ops = &stm32_pinctrl_ops;
1216b38386fbSEtienne Carriere 	pinconf->priv = &loc_conf->array_ref;
1217b38386fbSEtienne Carriere 
1218b38386fbSEtienne Carriere 	loc_conf->array_ref.count = pin_count;
1219b38386fbSEtienne Carriere 	pinctrl = loc_conf->array_ref.pinctrl;
1220b38386fbSEtienne Carriere 
1221b38386fbSEtienne Carriere 	count = 0;
1222b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1223b38386fbSEtienne Carriere 		int found = 0;
1224b38386fbSEtienne Carriere 
1225b38386fbSEtienne Carriere 		found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count,
1226b38386fbSEtienne Carriere 					     pin_count - count);
1227b38386fbSEtienne Carriere 		if (found <= 0 && found > ((int)pin_count - count)) {
1228b38386fbSEtienne Carriere 			/* We can't recover from an error here so let's panic */
1229b38386fbSEtienne Carriere 			panic();
1230b38386fbSEtienne Carriere 		}
1231b38386fbSEtienne Carriere 
1232b38386fbSEtienne Carriere 		count += found;
1233b38386fbSEtienne Carriere 	}
1234b38386fbSEtienne Carriere 
1235b38386fbSEtienne Carriere 	*out_pinconf = pinconf;
1236b38386fbSEtienne Carriere 
1237b38386fbSEtienne Carriere 	return TEE_SUCCESS;
1238b38386fbSEtienne Carriere }
1239b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
1240b38386fbSEtienne Carriere 
1241bfc43b68SGatien Chevallier static void stm32_gpio_get_conf_sec(struct stm32_gpio_bank *bank)
1242bfc43b68SGatien Chevallier {
1243bfc43b68SGatien Chevallier 	if (bank->sec_support) {
1244bfc43b68SGatien Chevallier 		clk_enable(bank->clock);
1245bfc43b68SGatien Chevallier 		bank->seccfgr = io_read32(bank->base + GPIO_SECR_OFFSET);
1246bfc43b68SGatien Chevallier 		clk_disable(bank->clock);
1247bfc43b68SGatien Chevallier 	}
1248bfc43b68SGatien Chevallier }
1249bfc43b68SGatien Chevallier 
1250bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank)
1251bd03c8c3SGatien Chevallier {
1252bd03c8c3SGatien Chevallier 	if (bank->sec_support) {
1253bd03c8c3SGatien Chevallier 		clk_enable(bank->clock);
1254bd03c8c3SGatien Chevallier 		io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr);
1255bd03c8c3SGatien Chevallier 		clk_disable(bank->clock);
1256bd03c8c3SGatien Chevallier 	}
1257bd03c8c3SGatien Chevallier }
1258bd03c8c3SGatien Chevallier 
1259bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_resume(void)
1260bfc43b68SGatien Chevallier {
1261bfc43b68SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1262bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1263bfc43b68SGatien Chevallier 
1264bfc43b68SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1265bfc43b68SGatien Chevallier 		if (bank->rif_cfg) {
1266bfc43b68SGatien Chevallier 			if (!bank->is_tdcid)
1267bfc43b68SGatien Chevallier 				continue;
1268bfc43b68SGatien Chevallier 
1269bfc43b68SGatien Chevallier 			bank->rif_cfg->access_mask[0] = GENMASK_32(bank->ngpios,
1270bfc43b68SGatien Chevallier 								   0);
1271bfc43b68SGatien Chevallier 
1272*a72f07daSEtienne Carriere 			res = apply_rif_config(bank,
1273*a72f07daSEtienne Carriere 					       bank->rif_cfg->access_mask[0]);
1274bfc43b68SGatien Chevallier 			if (res) {
1275bfc43b68SGatien Chevallier 				EMSG("Failed to set GPIO bank %c RIF config",
1276bfc43b68SGatien Chevallier 				     'A' + bank->bank_id);
1277bfc43b68SGatien Chevallier 				return res;
1278bfc43b68SGatien Chevallier 			}
1279bfc43b68SGatien Chevallier 		} else {
1280bfc43b68SGatien Chevallier 			stm32_gpio_set_conf_sec(bank);
1281bfc43b68SGatien Chevallier 		}
1282bfc43b68SGatien Chevallier 	}
1283bfc43b68SGatien Chevallier 
1284bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
1285bfc43b68SGatien Chevallier }
1286bfc43b68SGatien Chevallier 
1287bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_suspend(void)
1288bfc43b68SGatien Chevallier {
1289bfc43b68SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1290bfc43b68SGatien Chevallier 
1291bfc43b68SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1292bfc43b68SGatien Chevallier 		if (bank->rif_cfg) {
1293bfc43b68SGatien Chevallier 			if (bank->is_tdcid)
1294bfc43b68SGatien Chevallier 				stm32_gpio_save_rif_config(bank);
1295bfc43b68SGatien Chevallier 		} else {
1296bfc43b68SGatien Chevallier 			stm32_gpio_get_conf_sec(bank);
1297bfc43b68SGatien Chevallier 		}
1298bfc43b68SGatien Chevallier 	}
1299bfc43b68SGatien Chevallier 
1300bfc43b68SGatien Chevallier 	return TEE_SUCCESS;
1301bfc43b68SGatien Chevallier }
1302bfc43b68SGatien Chevallier 
1303bfc43b68SGatien Chevallier static TEE_Result
1304bfc43b68SGatien Chevallier stm32_gpio_sec_config_pm(enum pm_op op, unsigned int pm_hint,
1305bfc43b68SGatien Chevallier 			 const struct pm_callback_handle *hdl __unused)
1306bfc43b68SGatien Chevallier {
1307bfc43b68SGatien Chevallier 	TEE_Result ret = TEE_ERROR_GENERIC;
1308bfc43b68SGatien Chevallier 
1309bfc43b68SGatien Chevallier 	if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
1310bfc43b68SGatien Chevallier 		return TEE_SUCCESS;
1311bfc43b68SGatien Chevallier 
1312bfc43b68SGatien Chevallier 	if (op == PM_OP_RESUME)
1313bfc43b68SGatien Chevallier 		ret = stm32_gpio_sec_config_resume();
1314bfc43b68SGatien Chevallier 	else
1315bfc43b68SGatien Chevallier 		ret = stm32_gpio_sec_config_suspend();
1316bfc43b68SGatien Chevallier 
1317bfc43b68SGatien Chevallier 	return ret;
1318bfc43b68SGatien Chevallier }
1319bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(stm32_gpio_sec_config_pm);
1320bfc43b68SGatien Chevallier 
1321bd03c8c3SGatien Chevallier /*
1322bd03c8c3SGatien Chevallier  * Several pinctrl nodes can be probed. Their bank will be put in the unique
1323bd03c8c3SGatien Chevallier  * bank_list. To avoid multiple configuration set for a bank when looping
1324bd03c8c3SGatien Chevallier  * over each bank in the bank list, ready is set to true when a bank is
1325bd03c8c3SGatien Chevallier  * configured. Therefore, during other bank probes, the configuration won't
1326bd03c8c3SGatien Chevallier  * be set again.
1327bd03c8c3SGatien Chevallier  */
1328bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void)
1329bd03c8c3SGatien Chevallier {
1330bd03c8c3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1331bd03c8c3SGatien Chevallier 	struct stm32_gpio_bank *bank = NULL;
1332bd03c8c3SGatien Chevallier 
1333bd03c8c3SGatien Chevallier 	STAILQ_FOREACH(bank, &bank_list, link) {
1334bd03c8c3SGatien Chevallier 		if (bank->ready)
1335bd03c8c3SGatien Chevallier 			continue;
1336bd03c8c3SGatien Chevallier 
1337bd03c8c3SGatien Chevallier 		if (bank->rif_cfg) {
1338*a72f07daSEtienne Carriere 			res = apply_rif_config(bank,
1339*a72f07daSEtienne Carriere 					       bank->rif_cfg->access_mask[0]);
1340bd03c8c3SGatien Chevallier 			if (res) {
1341bd03c8c3SGatien Chevallier 				EMSG("Failed to set GPIO bank %c RIF config",
1342bd03c8c3SGatien Chevallier 				     'A' + bank->bank_id);
1343bd03c8c3SGatien Chevallier 				STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank,
1344bd03c8c3SGatien Chevallier 					      link);
13459def1fb7SGatien Chevallier 				free(bank);
1346bd03c8c3SGatien Chevallier 				return res;
1347bd03c8c3SGatien Chevallier 			}
1348bd03c8c3SGatien Chevallier 		} else {
1349bd03c8c3SGatien Chevallier 			stm32_gpio_set_conf_sec(bank);
1350bd03c8c3SGatien Chevallier 		}
1351bd03c8c3SGatien Chevallier 
1352bd03c8c3SGatien Chevallier 		bank->ready = true;
1353bd03c8c3SGatien Chevallier 	}
1354bd03c8c3SGatien Chevallier 
1355bd03c8c3SGatien Chevallier 	return TEE_SUCCESS;
1356bd03c8c3SGatien Chevallier }
1357bd03c8c3SGatien Chevallier 
13580e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
13590e0435e2SEtienne Carriere 				      const void *compat_data)
13600e0435e2SEtienne Carriere {
1361bfc43b68SGatien Chevallier 	static bool pm_register;
1362b38386fbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1363b38386fbSEtienne Carriere 
13640e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
1365b38386fbSEtienne Carriere 	res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
1366b38386fbSEtienne Carriere 	if (res)
1367b38386fbSEtienne Carriere 		return res;
1368b38386fbSEtienne Carriere 
1369bd03c8c3SGatien Chevallier 	if (STAILQ_EMPTY(&bank_list))
1370bd03c8c3SGatien Chevallier 		DMSG("no gpio bank for that driver");
1371bd03c8c3SGatien Chevallier 	else if (apply_sec_cfg())
1372bd03c8c3SGatien Chevallier 		panic();
1373bd03c8c3SGatien Chevallier 
1374bfc43b68SGatien Chevallier 	if (!pm_register) {
1375bfc43b68SGatien Chevallier 		/*
1376bfc43b68SGatien Chevallier 		 * Register to PM once for all probed banks to restore
1377bfc43b68SGatien Chevallier 		 * their secure configuration.
1378bfc43b68SGatien Chevallier 		 */
1379bfc43b68SGatien Chevallier 		register_pm_driver_cb(stm32_gpio_sec_config_pm, NULL,
1380bfc43b68SGatien Chevallier 				      "stm32-gpio-secure-config");
1381bfc43b68SGatien Chevallier 		pm_register = true;
1382bfc43b68SGatien Chevallier 	}
1383bfc43b68SGatien Chevallier 
1384b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1385b38386fbSEtienne Carriere 	res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
1386b38386fbSEtienne Carriere 					(void *)compat_data);
1387b38386fbSEtienne Carriere 	if (res)
1388bd03c8c3SGatien Chevallier 		panic();
1389b38386fbSEtienne Carriere #endif
1390b38386fbSEtienne Carriere 
1391b38386fbSEtienne Carriere 	return TEE_SUCCESS;
13920e0435e2SEtienne Carriere }
13930e0435e2SEtienne Carriere 
13940e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
1395e569f6adSEtienne Carriere 	{
1396e569f6adSEtienne Carriere 		.compatible = "st,stm32mp135-pinctrl",
1397b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1398b4893304SGatien Chevallier 			.secure_control = true,
1399bd03c8c3SGatien Chevallier 			.secure_extended = false,
1400b4893304SGatien Chevallier 		},
1401e569f6adSEtienne Carriere 	},
1402e569f6adSEtienne Carriere 	{
1403e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-pinctrl",
1404b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1405b4893304SGatien Chevallier 			.secure_control = false,
1406bd03c8c3SGatien Chevallier 			.secure_extended = false,
1407b4893304SGatien Chevallier 		},
1408e569f6adSEtienne Carriere 	},
1409e569f6adSEtienne Carriere 	{
1410e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-z-pinctrl",
1411b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
1412b4893304SGatien Chevallier 			.gpioz = true,
1413b4893304SGatien Chevallier 			.secure_control = true,
1414bd03c8c3SGatien Chevallier 			.secure_extended = false,
1415bd03c8c3SGatien Chevallier 		},
1416bd03c8c3SGatien Chevallier 	},
1417bd03c8c3SGatien Chevallier 	{
1418bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-pinctrl",
1419bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1420bd03c8c3SGatien Chevallier 			.secure_control = true,
1421bd03c8c3SGatien Chevallier 			.secure_extended = true,
1422bd03c8c3SGatien Chevallier 		},
1423bd03c8c3SGatien Chevallier 	},
1424bd03c8c3SGatien Chevallier 	{
1425bd03c8c3SGatien Chevallier 		.compatible = "st,stm32mp257-z-pinctrl",
1426bd03c8c3SGatien Chevallier 		.compat_data = &(struct bank_compat){
1427bd03c8c3SGatien Chevallier 			.gpioz = true,
1428bd03c8c3SGatien Chevallier 			.secure_control = true,
1429bd03c8c3SGatien Chevallier 			.secure_extended = true,
1430b4893304SGatien Chevallier 		},
1431e569f6adSEtienne Carriere 	},
14320e0435e2SEtienne Carriere 	{ }
14330e0435e2SEtienne Carriere };
14340e0435e2SEtienne Carriere 
14350e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
14360e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
14370e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
14380e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
14390e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
14400e0435e2SEtienne Carriere };
1441