xref: /optee_os/core/drivers/stm32_gpio.c (revision b4893304e2295529a6b98658248a6fced2ad3870)
14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
24b5e93edSEtienne Carriere /*
39818a481SEtienne Carriere  * Copyright (c) 2017-2023, STMicroelectronics
44b5e93edSEtienne Carriere  *
54b5e93edSEtienne Carriere  * STM32 GPIO driver is used as pin controller for stm32mp SoCs.
64b5e93edSEtienne Carriere  */
74b5e93edSEtienne Carriere 
84b5e93edSEtienne Carriere #include <assert.h>
969715ce9SEtienne Carriere #include <compiler.h>
1097391ffbSEtienne Carriere #include <drivers/clk.h>
1197391ffbSEtienne Carriere #include <drivers/clk_dt.h>
12420a32c5SEtienne Carriere #include <drivers/gpio.h>
13b38386fbSEtienne Carriere #include <drivers/pinctrl.h>
144b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h>
15*b4893304SGatien Chevallier #include <dt-bindings/gpio/stm32mp_gpio.h>
164b5e93edSEtienne Carriere #include <io.h>
174b5e93edSEtienne Carriere #include <kernel/dt.h>
1865401337SJens Wiklander #include <kernel/boot.h>
194b5e93edSEtienne Carriere #include <kernel/panic.h>
204b5e93edSEtienne Carriere #include <kernel/spinlock.h>
21a2fc83d1SJerome Forissier #include <libfdt.h>
224b5e93edSEtienne Carriere #include <mm/core_memprot.h>
234b5e93edSEtienne Carriere #include <stdbool.h>
2469715ce9SEtienne Carriere #include <stdint.h>
254b5e93edSEtienne Carriere #include <stm32_util.h>
269818a481SEtienne Carriere #include <sys/queue.h>
274b5e93edSEtienne Carriere #include <trace.h>
284b5e93edSEtienne Carriere #include <util.h>
294b5e93edSEtienne Carriere 
301001585eSEtienne Carriere #ifndef CFG_DRIVERS_GPIO
311001585eSEtienne Carriere #error stm32_gpio driver expects CFG_DRIVERS_GPIO
321001585eSEtienne Carriere #endif
331001585eSEtienne Carriere 
344b5e93edSEtienne Carriere #define GPIO_PIN_MAX		15
354b5e93edSEtienne Carriere 
365eed568cSGatien Chevallier #define GPIO_MODER_OFFSET	U(0x00)
375eed568cSGatien Chevallier #define GPIO_OTYPER_OFFSET	U(0x04)
385eed568cSGatien Chevallier #define GPIO_OSPEEDR_OFFSET	U(0x08)
395eed568cSGatien Chevallier #define GPIO_PUPDR_OFFSET	U(0x0c)
405eed568cSGatien Chevallier #define GPIO_IDR_OFFSET		U(0x10)
415eed568cSGatien Chevallier #define GPIO_ODR_OFFSET		U(0x14)
425eed568cSGatien Chevallier #define GPIO_BSRR_OFFSET	U(0x18)
435eed568cSGatien Chevallier #define GPIO_AFRL_OFFSET	U(0x20)
445eed568cSGatien Chevallier #define GPIO_AFRH_OFFSET	U(0x24)
455eed568cSGatien Chevallier #define GPIO_SECR_OFFSET	U(0x30)
464b5e93edSEtienne Carriere 
475eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT	U(0x8)
484b5e93edSEtienne Carriere 
494b5e93edSEtienne Carriere #define GPIO_MODE_MASK		GENMASK_32(1, 0)
504b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK	GENMASK_32(1, 0)
514b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK	GENMASK_32(1, 0)
52729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK	GENMASK_32(3, 0)
534b5e93edSEtienne Carriere 
545eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT	U(12)
554b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK	GENMASK_32(16, 12)
565eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT	U(8)
574b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK	GENMASK_32(11, 8)
584b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK	GENMASK_32(7, 0)
594b5e93edSEtienne Carriere 
609818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0	"GPIOA"
619818a481SEtienne Carriere 
6269715ce9SEtienne Carriere #define GPIO_MODE_INPUT		U(0x0)
6369715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT	U(0x1)
6469715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE	U(0x2)
6569715ce9SEtienne Carriere #define GPIO_MODE_ANALOG	U(0x3)
6669715ce9SEtienne Carriere 
6769715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL	U(0x0)
6869715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN	U(0x1)
6969715ce9SEtienne Carriere 
7069715ce9SEtienne Carriere #define GPIO_OSPEED_LOW		U(0x0)
7169715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM	U(0x1)
7269715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH	U(0x2)
7369715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH	U(0x3)
7469715ce9SEtienne Carriere 
7569715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL	U(0x0)
7669715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP	U(0x1)
7769715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN	U(0x2)
7869715ce9SEtienne Carriere 
7969715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW	U(0x0)
8069715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH	U(0x1)
8169715ce9SEtienne Carriere 
8269715ce9SEtienne Carriere /*
8369715ce9SEtienne Carriere  * GPIO configuration description structured as single 16bit word
8469715ce9SEtienne Carriere  * for efficient save/restore when GPIO pin suspends or resumes.
8569715ce9SEtienne Carriere  *
8669715ce9SEtienne Carriere  * @mode: One of GPIO_MODE_*
8769715ce9SEtienne Carriere  * @otype: One of GPIO_OTYPE_*
8869715ce9SEtienne Carriere  * @ospeed: One of GPIO_OSPEED_*
8969715ce9SEtienne Carriere  * @pupd: One of GPIO_PUPD_*
9069715ce9SEtienne Carriere  * @od: One of GPIO_OD_*
9169715ce9SEtienne Carriere  * @af: Alternate function numerical ID between 0 and 15
9269715ce9SEtienne Carriere  */
9369715ce9SEtienne Carriere struct gpio_cfg {
9469715ce9SEtienne Carriere 	uint16_t mode:		2;
9569715ce9SEtienne Carriere 	uint16_t otype:		1;
9669715ce9SEtienne Carriere 	uint16_t ospeed:	2;
9769715ce9SEtienne Carriere 	uint16_t pupd:		2;
9869715ce9SEtienne Carriere 	uint16_t od:		1;
9969715ce9SEtienne Carriere 	uint16_t af:		4;
10069715ce9SEtienne Carriere };
10169715ce9SEtienne Carriere 
10269715ce9SEtienne Carriere /*
10369715ce9SEtienne Carriere  * Description of a pin and its muxing
10469715ce9SEtienne Carriere  *
10569715ce9SEtienne Carriere  * @bank: GPIO bank identifier as assigned by the platform
10669715ce9SEtienne Carriere  * @pin: Pin number in the GPIO bank
10769715ce9SEtienne Carriere  * @cfg: Pin configuration
10869715ce9SEtienne Carriere  */
10969715ce9SEtienne Carriere struct stm32_pinctrl {
11069715ce9SEtienne Carriere 	uint8_t bank;
11169715ce9SEtienne Carriere 	uint8_t pin;
11269715ce9SEtienne Carriere 	struct gpio_cfg cfg;
11369715ce9SEtienne Carriere };
11469715ce9SEtienne Carriere 
115b38386fbSEtienne Carriere /*
116b38386fbSEtienne Carriere  * struct stm32_pinctrl_array - Array of pins in a pin control state
117b38386fbSEtienne Carriere  * @count: Number of cells in @pinctrl
118b38386fbSEtienne Carriere  * @pinctrl: Pin control configuration
119b38386fbSEtienne Carriere  */
120b38386fbSEtienne Carriere struct stm32_pinctrl_array {
121b38386fbSEtienne Carriere 	size_t count;
122b38386fbSEtienne Carriere 	struct stm32_pinctrl pinctrl[];
123b38386fbSEtienne Carriere };
124b38386fbSEtienne Carriere 
1259818a481SEtienne Carriere /**
1269818a481SEtienne Carriere  * struct stm32_gpio_bank - GPIO bank instance
1279818a481SEtienne Carriere  *
1289818a481SEtienne Carriere  * @base: base address of the GPIO controller registers.
1299818a481SEtienne Carriere  * @clock: clock identifier.
130420a32c5SEtienne Carriere  * @gpio_chip: GPIO chip reference for that GPIO bank
1319818a481SEtienne Carriere  * @ngpios: number of GPIOs.
1329818a481SEtienne Carriere  * @bank_id: Id of the bank.
1339818a481SEtienne Carriere  * @lock: lock protecting the GPIO bank access.
1349818a481SEtienne Carriere  * @sec_support: True if bank supports pin security protection, otherwise false
1359818a481SEtienne Carriere  * @link: Link in bank list
1369818a481SEtienne Carriere  */
1379818a481SEtienne Carriere struct stm32_gpio_bank {
1389818a481SEtienne Carriere 	vaddr_t base;
1399818a481SEtienne Carriere 	struct clk *clock;
140420a32c5SEtienne Carriere 	struct gpio_chip gpio_chip;
1419818a481SEtienne Carriere 	unsigned int ngpios;
1429818a481SEtienne Carriere 	unsigned int bank_id;
1439818a481SEtienne Carriere 	unsigned int lock;
144*b4893304SGatien Chevallier 	bool sec_support;
1459818a481SEtienne Carriere 	STAILQ_ENTRY(stm32_gpio_bank) link;
1469818a481SEtienne Carriere };
1479818a481SEtienne Carriere 
148*b4893304SGatien Chevallier /**
149e569f6adSEtienne Carriere  * Compatibility information of supported banks
150*b4893304SGatien Chevallier  *
151*b4893304SGatien Chevallier  * @gpioz: True if bank is a GPIOZ bank
152*b4893304SGatien Chevallier  * @secure_control: Identify GPIO security bank capability.
153e569f6adSEtienne Carriere  */
154e569f6adSEtienne Carriere struct bank_compat {
155e569f6adSEtienne Carriere 	bool gpioz;
156*b4893304SGatien Chevallier 	bool secure_control;
157e569f6adSEtienne Carriere };
158e569f6adSEtienne Carriere 
1594b5e93edSEtienne Carriere static unsigned int gpio_lock;
1604b5e93edSEtienne Carriere 
1619818a481SEtienne Carriere static STAILQ_HEAD(, stm32_gpio_bank) bank_list =
1629818a481SEtienne Carriere 		STAILQ_HEAD_INITIALIZER(bank_list);
1639818a481SEtienne Carriere 
164420a32c5SEtienne Carriere static bool is_stm32_gpio_chip(struct gpio_chip *chip);
165420a32c5SEtienne Carriere 
166420a32c5SEtienne Carriere static struct stm32_gpio_bank *gpio_chip_to_bank(struct gpio_chip *chip)
167420a32c5SEtienne Carriere {
168420a32c5SEtienne Carriere 	return container_of(chip, struct stm32_gpio_bank, gpio_chip);
169420a32c5SEtienne Carriere }
170420a32c5SEtienne Carriere 
171420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
172420a32c5SEtienne Carriere 					    unsigned int gpio_pin)
173420a32c5SEtienne Carriere {
174420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
175420a32c5SEtienne Carriere 	enum gpio_level level = GPIO_LEVEL_HIGH;
176420a32c5SEtienne Carriere 	unsigned int reg_offset = 0;
177420a32c5SEtienne Carriere 	unsigned int mode = 0;
178420a32c5SEtienne Carriere 
179420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
1802fd102ebSEtienne Carriere 
1812fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
1822fd102ebSEtienne Carriere 		panic();
183420a32c5SEtienne Carriere 
184420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
185420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
186420a32c5SEtienne Carriere 
187420a32c5SEtienne Carriere 	switch (mode) {
188420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
189420a32c5SEtienne Carriere 		reg_offset = GPIO_IDR_OFFSET;
190420a32c5SEtienne Carriere 		break;
191420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
192420a32c5SEtienne Carriere 		reg_offset = GPIO_ODR_OFFSET;
193420a32c5SEtienne Carriere 		break;
194420a32c5SEtienne Carriere 	default:
195420a32c5SEtienne Carriere 		panic();
196420a32c5SEtienne Carriere 	}
197420a32c5SEtienne Carriere 
198420a32c5SEtienne Carriere 	if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
199420a32c5SEtienne Carriere 		level = GPIO_LEVEL_HIGH;
200420a32c5SEtienne Carriere 	else
201420a32c5SEtienne Carriere 		level = GPIO_LEVEL_LOW;
202420a32c5SEtienne Carriere 
203420a32c5SEtienne Carriere 	clk_disable(bank->clock);
204420a32c5SEtienne Carriere 
205420a32c5SEtienne Carriere 	return level;
206420a32c5SEtienne Carriere }
207420a32c5SEtienne Carriere 
208420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
209420a32c5SEtienne Carriere 				 enum gpio_level level)
210420a32c5SEtienne Carriere {
211420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
212420a32c5SEtienne Carriere 
213420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2142fd102ebSEtienne Carriere 
2152fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2162fd102ebSEtienne Carriere 		panic();
217420a32c5SEtienne Carriere 
218420a32c5SEtienne Carriere 	assert(((io_read32(bank->base + GPIO_MODER_OFFSET) >>
219420a32c5SEtienne Carriere 		 (gpio_pin << 1)) & GPIO_MODE_MASK) == GPIO_MODE_OUTPUT);
220420a32c5SEtienne Carriere 
221420a32c5SEtienne Carriere 	if (level == GPIO_LEVEL_HIGH)
222420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
223420a32c5SEtienne Carriere 	else
224420a32c5SEtienne Carriere 		io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
225420a32c5SEtienne Carriere 
226420a32c5SEtienne Carriere 	clk_disable(bank->clock);
227420a32c5SEtienne Carriere }
228420a32c5SEtienne Carriere 
229420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
230420a32c5SEtienne Carriere 					      unsigned int gpio_pin)
231420a32c5SEtienne Carriere {
232420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
233420a32c5SEtienne Carriere 	uint32_t mode = 0;
234420a32c5SEtienne Carriere 
235420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
2362fd102ebSEtienne Carriere 
2372fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2382fd102ebSEtienne Carriere 		panic();
239420a32c5SEtienne Carriere 
240420a32c5SEtienne Carriere 	mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
241420a32c5SEtienne Carriere 	       GPIO_MODE_MASK;
242420a32c5SEtienne Carriere 
243420a32c5SEtienne Carriere 	clk_disable(bank->clock);
244420a32c5SEtienne Carriere 
245420a32c5SEtienne Carriere 	switch (mode) {
246420a32c5SEtienne Carriere 	case GPIO_MODE_INPUT:
247420a32c5SEtienne Carriere 		return GPIO_DIR_IN;
248420a32c5SEtienne Carriere 	case GPIO_MODE_OUTPUT:
249420a32c5SEtienne Carriere 		return GPIO_DIR_OUT;
250420a32c5SEtienne Carriere 	default:
251420a32c5SEtienne Carriere 		panic();
252420a32c5SEtienne Carriere 	}
253420a32c5SEtienne Carriere }
254420a32c5SEtienne Carriere 
255420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
256420a32c5SEtienne Carriere 				     unsigned int gpio_pin,
257420a32c5SEtienne Carriere 				     enum gpio_dir direction)
258420a32c5SEtienne Carriere {
259420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
260420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
261420a32c5SEtienne Carriere 	uint32_t mode = 0;
262420a32c5SEtienne Carriere 
263420a32c5SEtienne Carriere 	assert(gpio_pin < bank->ngpios);
264420a32c5SEtienne Carriere 
265420a32c5SEtienne Carriere 	if (direction == GPIO_DIR_IN)
266420a32c5SEtienne Carriere 		mode = GPIO_MODE_INPUT;
267420a32c5SEtienne Carriere 	else
268420a32c5SEtienne Carriere 		mode = GPIO_MODE_OUTPUT;
269420a32c5SEtienne Carriere 
2702fd102ebSEtienne Carriere 	if (clk_enable(bank->clock))
2712fd102ebSEtienne Carriere 		panic();
272420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
273420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
274420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
275420a32c5SEtienne Carriere 			SHIFT_U32(mode, gpio_pin << 1));
276420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
277420a32c5SEtienne Carriere 	clk_disable(bank->clock);
278420a32c5SEtienne Carriere }
279420a32c5SEtienne Carriere 
280420a32c5SEtienne Carriere static void stm32_gpio_put_gpio(struct gpio_chip *chip __maybe_unused,
281420a32c5SEtienne Carriere 				struct gpio *gpio)
282420a32c5SEtienne Carriere {
283420a32c5SEtienne Carriere 	assert(is_stm32_gpio_chip(chip));
284420a32c5SEtienne Carriere 	free(gpio);
285420a32c5SEtienne Carriere }
286420a32c5SEtienne Carriere 
287420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
288420a32c5SEtienne Carriere 	.get_direction = stm32_gpio_get_direction,
289420a32c5SEtienne Carriere 	.set_direction = stm32_gpio_set_direction,
290420a32c5SEtienne Carriere 	.get_value = stm32_gpio_get_level,
291420a32c5SEtienne Carriere 	.set_value = stm32_gpio_set_level,
292420a32c5SEtienne Carriere 	.put = stm32_gpio_put_gpio,
293420a32c5SEtienne Carriere };
294420a32c5SEtienne Carriere 
295420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
296420a32c5SEtienne Carriere {
297420a32c5SEtienne Carriere 	return chip && chip->ops == &stm32_gpio_ops;
298420a32c5SEtienne Carriere }
299420a32c5SEtienne Carriere 
300077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
3014b5e93edSEtienne Carriere {
302077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
3034b5e93edSEtienne Carriere 
304077d486eSEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
305077d486eSEtienne Carriere 		if (bank_id == bank->bank_id)
306077d486eSEtienne Carriere 			return bank;
307077d486eSEtienne Carriere 
308077d486eSEtienne Carriere 	panic();
309077d486eSEtienne Carriere }
310077d486eSEtienne Carriere 
311077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
312b38386fbSEtienne Carriere static void __maybe_unused get_gpio_cfg(uint32_t bank_id, uint32_t pin,
313b38386fbSEtienne Carriere 					struct gpio_cfg *cfg)
314077d486eSEtienne Carriere {
315077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
316077d486eSEtienne Carriere 
317077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
318077d486eSEtienne Carriere 		panic();
3194b5e93edSEtienne Carriere 
3204b5e93edSEtienne Carriere 	/*
3214b5e93edSEtienne Carriere 	 * Save GPIO configuration bits spread over the few bank registers.
3224b5e93edSEtienne Carriere 	 * 1bit fields are accessed at bit position being the pin index.
3234b5e93edSEtienne Carriere 	 * 2bit fields are accessed at bit position being twice the pin index.
3244b5e93edSEtienne Carriere 	 * 4bit fields are accessed at bit position being fourth the pin index
3254b5e93edSEtienne Carriere 	 * but accessed from 2 32bit registers at incremental addresses.
3264b5e93edSEtienne Carriere 	 */
327077d486eSEtienne Carriere 	cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
3284b5e93edSEtienne Carriere 		    GPIO_MODE_MASK;
3294b5e93edSEtienne Carriere 
330077d486eSEtienne Carriere 	cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
3314b5e93edSEtienne Carriere 
332077d486eSEtienne Carriere 	cfg->ospeed = (io_read32(bank->base +  GPIO_OSPEEDR_OFFSET) >>
333077d486eSEtienne Carriere 		       (pin << 1)) & GPIO_OSPEED_MASK;
3344b5e93edSEtienne Carriere 
335077d486eSEtienne Carriere 	cfg->pupd = (io_read32(bank->base +  GPIO_PUPDR_OFFSET) >> (pin << 1)) &
3364b5e93edSEtienne Carriere 		    GPIO_PUPD_PULL_MASK;
3374b5e93edSEtienne Carriere 
338077d486eSEtienne Carriere 	cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
3394b5e93edSEtienne Carriere 
3404b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT)
341077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
342077d486eSEtienne Carriere 			   (pin << 2)) & GPIO_ALTERNATE_MASK;
3434b5e93edSEtienne Carriere 	else
344077d486eSEtienne Carriere 		cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
3454b5e93edSEtienne Carriere 			   ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
3464b5e93edSEtienne Carriere 			  GPIO_ALTERNATE_MASK;
3474b5e93edSEtienne Carriere 
348077d486eSEtienne Carriere 	clk_disable(bank->clock);
3494b5e93edSEtienne Carriere }
3504b5e93edSEtienne Carriere 
3514b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
352077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
3534b5e93edSEtienne Carriere {
354077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
35598dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
3564b5e93edSEtienne Carriere 
357077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
358077d486eSEtienne Carriere 		panic();
35998dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
3604b5e93edSEtienne Carriere 
3614b5e93edSEtienne Carriere 	/* Load GPIO MODE value, 2bit value shifted by twice the pin number */
362077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
363bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, pin << 1),
364bed4582fSEtienne Carriere 			SHIFT_U32(cfg->mode, pin << 1));
3654b5e93edSEtienne Carriere 
3664b5e93edSEtienne Carriere 	/* Load GPIO Output TYPE value, 1bit shifted by pin number value */
367077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
368bed4582fSEtienne Carriere 			SHIFT_U32(cfg->otype, pin));
3694b5e93edSEtienne Carriere 
3704b5e93edSEtienne Carriere 	/* Load GPIO Output Speed confguration, 2bit value */
371077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
372bed4582fSEtienne Carriere 			SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
373bed4582fSEtienne Carriere 			SHIFT_U32(cfg->ospeed, pin << 1));
3744b5e93edSEtienne Carriere 
3754b5e93edSEtienne Carriere 	/* Load GPIO pull configuration, 2bit value */
376077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
377bed4582fSEtienne Carriere 			SHIFT_U32(cfg->pupd, pin << 1));
3784b5e93edSEtienne Carriere 
3794b5e93edSEtienne Carriere 	/* Load pin mux Alternate Function configuration, 4bit value */
3804b5e93edSEtienne Carriere 	if (pin < GPIO_ALT_LOWER_LIMIT) {
381077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
382bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
383bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, pin << 2));
3844b5e93edSEtienne Carriere 	} else {
3854b5e93edSEtienne Carriere 		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
3864b5e93edSEtienne Carriere 
387077d486eSEtienne Carriere 		io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
388bed4582fSEtienne Carriere 				SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
389bed4582fSEtienne Carriere 				SHIFT_U32(cfg->af, shift));
3904b5e93edSEtienne Carriere 	}
3914b5e93edSEtienne Carriere 
3924b5e93edSEtienne Carriere 	/* Load GPIO Output direction confuguration, 1bit */
393077d486eSEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
3944b5e93edSEtienne Carriere 
395c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
39698dfcedaSEtienne Carriere 	clk_disable(bank->clock);
3974b5e93edSEtienne Carriere }
3984b5e93edSEtienne Carriere 
3994b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
400b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
4014b5e93edSEtienne Carriere 				struct stm32_pinctrl *pinctrl, size_t count)
4024b5e93edSEtienne Carriere {
403b38386fbSEtienne Carriere 	const fdt32_t *cuint = NULL;
404b38386fbSEtienne Carriere 	const fdt32_t *slewrate = NULL;
40510bcbd6cSEtienne Carriere 	int len = 0;
40610bcbd6cSEtienne Carriere 	uint32_t i = 0;
4074b5e93edSEtienne Carriere 	uint32_t speed = GPIO_OSPEED_LOW;
4084b5e93edSEtienne Carriere 	uint32_t pull = GPIO_PUPD_NO_PULL;
4094b5e93edSEtienne Carriere 	size_t found = 0;
4104b5e93edSEtienne Carriere 
4114b5e93edSEtienne Carriere 	cuint = fdt_getprop(fdt, node, "pinmux", &len);
4124b5e93edSEtienne Carriere 	if (!cuint)
4134b5e93edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
4144b5e93edSEtienne Carriere 
4154b5e93edSEtienne Carriere 	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
4164b5e93edSEtienne Carriere 	if (slewrate)
4174b5e93edSEtienne Carriere 		speed = fdt32_to_cpu(*slewrate);
4184b5e93edSEtienne Carriere 
4194b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
4204b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_UP;
4214b5e93edSEtienne Carriere 	if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
4224b5e93edSEtienne Carriere 		pull = GPIO_PUPD_PULL_DOWN;
4234b5e93edSEtienne Carriere 
4244b5e93edSEtienne Carriere 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
42510bcbd6cSEtienne Carriere 		uint32_t pincfg = 0;
42610bcbd6cSEtienne Carriere 		uint32_t bank = 0;
42710bcbd6cSEtienne Carriere 		uint32_t pin = 0;
42810bcbd6cSEtienne Carriere 		uint32_t mode = 0;
4294b5e93edSEtienne Carriere 		uint32_t alternate = 0;
430322cf9e3SEtienne Carriere 		uint32_t odata = 0;
4314b5e93edSEtienne Carriere 		bool opendrain = false;
4324b5e93edSEtienne Carriere 
4334b5e93edSEtienne Carriere 		pincfg = fdt32_to_cpu(*cuint);
4344b5e93edSEtienne Carriere 		cuint++;
4354b5e93edSEtienne Carriere 
4364b5e93edSEtienne Carriere 		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
4374b5e93edSEtienne Carriere 
4384b5e93edSEtienne Carriere 		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
4394b5e93edSEtienne Carriere 
4404b5e93edSEtienne Carriere 		mode = pincfg & DT_GPIO_MODE_MASK;
4414b5e93edSEtienne Carriere 
4424b5e93edSEtienne Carriere 		switch (mode) {
4434b5e93edSEtienne Carriere 		case 0:
4444b5e93edSEtienne Carriere 			mode = GPIO_MODE_INPUT;
4454b5e93edSEtienne Carriere 			break;
4464b5e93edSEtienne Carriere 		case 1:
4474b5e93edSEtienne Carriere 		case 2:
4484b5e93edSEtienne Carriere 		case 3:
4494b5e93edSEtienne Carriere 		case 4:
4504b5e93edSEtienne Carriere 		case 5:
4514b5e93edSEtienne Carriere 		case 6:
4524b5e93edSEtienne Carriere 		case 7:
4534b5e93edSEtienne Carriere 		case 8:
4544b5e93edSEtienne Carriere 		case 9:
4554b5e93edSEtienne Carriere 		case 10:
4564b5e93edSEtienne Carriere 		case 11:
4574b5e93edSEtienne Carriere 		case 12:
4584b5e93edSEtienne Carriere 		case 13:
4594b5e93edSEtienne Carriere 		case 14:
4604b5e93edSEtienne Carriere 		case 15:
4614b5e93edSEtienne Carriere 		case 16:
4624b5e93edSEtienne Carriere 			alternate = mode - 1U;
4634b5e93edSEtienne Carriere 			mode = GPIO_MODE_ALTERNATE;
4644b5e93edSEtienne Carriere 			break;
4654b5e93edSEtienne Carriere 		case 17:
4664b5e93edSEtienne Carriere 			mode = GPIO_MODE_ANALOG;
4674b5e93edSEtienne Carriere 			break;
4684b5e93edSEtienne Carriere 		default:
4694b5e93edSEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
4704b5e93edSEtienne Carriere 			break;
4714b5e93edSEtienne Carriere 		}
4724b5e93edSEtienne Carriere 
4734b5e93edSEtienne Carriere 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
4744b5e93edSEtienne Carriere 			opendrain = true;
4754b5e93edSEtienne Carriere 
476322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-high", NULL) &&
477322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
478322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
479322cf9e3SEtienne Carriere 			odata = 1;
480322cf9e3SEtienne Carriere 		}
481322cf9e3SEtienne Carriere 
482322cf9e3SEtienne Carriere 		if (fdt_getprop(fdt, node, "output-low", NULL) &&
483322cf9e3SEtienne Carriere 		    mode == GPIO_MODE_INPUT) {
484322cf9e3SEtienne Carriere 			mode = GPIO_MODE_OUTPUT;
485322cf9e3SEtienne Carriere 			odata = 0;
486322cf9e3SEtienne Carriere 		}
487322cf9e3SEtienne Carriere 
4884b5e93edSEtienne Carriere 		if (found < count) {
4894b5e93edSEtienne Carriere 			struct stm32_pinctrl *ref = &pinctrl[found];
4904b5e93edSEtienne Carriere 
4914b5e93edSEtienne Carriere 			ref->bank = (uint8_t)bank;
4924b5e93edSEtienne Carriere 			ref->pin = (uint8_t)pin;
493b38386fbSEtienne Carriere 			ref->cfg.mode = mode;
494b38386fbSEtienne Carriere 			if (opendrain)
495b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
496b38386fbSEtienne Carriere 			else
497b38386fbSEtienne Carriere 				ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
498b38386fbSEtienne Carriere 			ref->cfg.ospeed = speed;
499b38386fbSEtienne Carriere 			ref->cfg.pupd = pull;
500b38386fbSEtienne Carriere 			ref->cfg.od = odata;
501b38386fbSEtienne Carriere 			ref->cfg.af = alternate;
5024b5e93edSEtienne Carriere 		}
5034b5e93edSEtienne Carriere 
5044b5e93edSEtienne Carriere 		found++;
5054b5e93edSEtienne Carriere 	}
5064b5e93edSEtienne Carriere 
5074b5e93edSEtienne Carriere 	return (int)found;
5084b5e93edSEtienne Carriere }
5094b5e93edSEtienne Carriere 
510b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
511b357d34fSEtienne Carriere 				    struct gpio **out_gpio)
512420a32c5SEtienne Carriere {
513b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
514420a32c5SEtienne Carriere 	struct stm32_gpio_bank *bank = data;
515420a32c5SEtienne Carriere 	struct gpio *gpio = NULL;
516420a32c5SEtienne Carriere 	unsigned int shift_1b = 0;
517420a32c5SEtienne Carriere 	unsigned int shift_2b = 0;
518420a32c5SEtienne Carriere 	uint32_t exceptions = 0;
519420a32c5SEtienne Carriere 	uint32_t otype = 0;
520420a32c5SEtienne Carriere 	uint32_t pupd = 0;
521420a32c5SEtienne Carriere 	uint32_t mode = 0;
522420a32c5SEtienne Carriere 
523b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
524b357d34fSEtienne Carriere 	if (res)
525b357d34fSEtienne Carriere 		return res;
526420a32c5SEtienne Carriere 
527420a32c5SEtienne Carriere 	if (gpio->pin >= bank->ngpios) {
528420a32c5SEtienne Carriere 		DMSG("Invalid GPIO reference");
529420a32c5SEtienne Carriere 		free(gpio);
530b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
531420a32c5SEtienne Carriere 	}
532420a32c5SEtienne Carriere 
533420a32c5SEtienne Carriere 	shift_1b = gpio->pin;
534420a32c5SEtienne Carriere 	shift_2b = SHIFT_U32(gpio->pin, 1);
535420a32c5SEtienne Carriere 
536420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_PULL_UP)
537420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_UP;
538420a32c5SEtienne Carriere 	else if (gpio->dt_flags & GPIO_PULL_DOWN)
539420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_PULL_DOWN;
540420a32c5SEtienne Carriere 	else
541420a32c5SEtienne Carriere 		pupd = GPIO_PUPD_NO_PULL;
542420a32c5SEtienne Carriere 
543420a32c5SEtienne Carriere 	if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
544420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_OPEN_DRAIN;
545420a32c5SEtienne Carriere 	else
546420a32c5SEtienne Carriere 		otype = GPIO_OTYPE_PUSH_PULL;
547420a32c5SEtienne Carriere 
548420a32c5SEtienne Carriere 	if (clk_enable(bank->clock))
549420a32c5SEtienne Carriere 		panic();
550420a32c5SEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
551420a32c5SEtienne Carriere 
552420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
553420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_MODE_MASK, shift_2b),
554420a32c5SEtienne Carriere 			SHIFT_U32(mode, shift_2b));
555420a32c5SEtienne Carriere 
556420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
557420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
558420a32c5SEtienne Carriere 			SHIFT_U32(otype, shift_1b));
559420a32c5SEtienne Carriere 
560420a32c5SEtienne Carriere 	io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
561420a32c5SEtienne Carriere 			SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
562420a32c5SEtienne Carriere 			SHIFT_U32(pupd, shift_2b));
563420a32c5SEtienne Carriere 
564420a32c5SEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
565420a32c5SEtienne Carriere 	clk_disable(bank->clock);
566420a32c5SEtienne Carriere 
567420a32c5SEtienne Carriere 	gpio->chip = &bank->gpio_chip;
568420a32c5SEtienne Carriere 
569b357d34fSEtienne Carriere 	*out_gpio = gpio;
570420a32c5SEtienne Carriere 
571b357d34fSEtienne Carriere 	return TEE_SUCCESS;
572420a32c5SEtienne Carriere }
573420a32c5SEtienne Carriere 
5749818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
5759818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
5769818a481SEtienne Carriere {
5779818a481SEtienne Carriere 	const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
5789818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
5799818a481SEtienne Carriere 	int len = 0;
5809818a481SEtienne Carriere 
5819818a481SEtienne Carriere 	/* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
5829818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
5839818a481SEtienne Carriere 	if (!cuint || (len != dt_name_len + 1))
5849818a481SEtienne Carriere 		panic("Missing/wrong st,bank-name property");
5859818a481SEtienne Carriere 
5869818a481SEtienne Carriere 	if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
5879818a481SEtienne Carriere 	    strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
5889818a481SEtienne Carriere 		panic("Wrong st,bank-name property");
5899818a481SEtienne Carriere 
5909818a481SEtienne Carriere 	return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
5919818a481SEtienne Carriere }
5929818a481SEtienne Carriere 
5939818a481SEtienne Carriere /*
5949818a481SEtienne Carriere  * Return whether or not the GPIO bank related to a DT node is already
5959818a481SEtienne Carriere  * registered in the GPIO bank link.
5969818a481SEtienne Carriere  */
5979818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
5989818a481SEtienne Carriere {
5999818a481SEtienne Carriere 	unsigned int bank_id = dt_get_bank_id(fdt, node);
6009818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
6019818a481SEtienne Carriere 
6029818a481SEtienne Carriere 	STAILQ_FOREACH(bank, &bank_list, link)
6039818a481SEtienne Carriere 		if (bank->bank_id == bank_id)
6049818a481SEtienne Carriere 			return true;
6059818a481SEtienne Carriere 
6069818a481SEtienne Carriere 	return false;
6079818a481SEtienne Carriere }
6089818a481SEtienne Carriere 
6099818a481SEtienne Carriere /* Get GPIO bank information from the DT */
6109818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
611e569f6adSEtienne Carriere 				     const void *compat_data,
6129818a481SEtienne Carriere 				     int range_offset,
6139818a481SEtienne Carriere 				     struct stm32_gpio_bank **out_bank)
6149818a481SEtienne Carriere {
615e569f6adSEtienne Carriere 	const struct bank_compat *compat = compat_data;
6169818a481SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
6179818a481SEtienne Carriere 	struct stm32_gpio_bank *bank = NULL;
6189818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6199818a481SEtienne Carriere 	struct io_pa_va pa_va = { };
6209818a481SEtienne Carriere 	struct clk *clk = NULL;
6219818a481SEtienne Carriere 	size_t blen = 0;
6229818a481SEtienne Carriere 	paddr_t pa = 0;
6239818a481SEtienne Carriere 	int len = 0;
6249818a481SEtienne Carriere 	int i = 0;
6259818a481SEtienne Carriere 
6269818a481SEtienne Carriere 	assert(out_bank);
6279818a481SEtienne Carriere 
6289818a481SEtienne Carriere 	/* Probe deferrable devices first */
6299818a481SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
6309818a481SEtienne Carriere 	if (res)
6319818a481SEtienne Carriere 		return res;
6329818a481SEtienne Carriere 
6339818a481SEtienne Carriere 	bank = calloc(1, sizeof(*bank));
6349818a481SEtienne Carriere 	if (!bank)
6359818a481SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
6369818a481SEtienne Carriere 
6379818a481SEtienne Carriere 	/*
6389818a481SEtienne Carriere 	 * Do not rely *only* on the "reg" property to get the address,
6399818a481SEtienne Carriere 	 * but consider also the "ranges" translation property
6409818a481SEtienne Carriere 	 */
6419818a481SEtienne Carriere 	pa = fdt_reg_base_address(fdt, node);
6429818a481SEtienne Carriere 	if (pa == DT_INFO_INVALID_REG)
6439818a481SEtienne Carriere 		panic("missing reg property");
6449818a481SEtienne Carriere 
6459818a481SEtienne Carriere 	pa_va.pa = pa + range_offset;
6469818a481SEtienne Carriere 
6479818a481SEtienne Carriere 	blen = fdt_reg_size(fdt, node);
6489818a481SEtienne Carriere 	if (blen == DT_INFO_INVALID_REG_SIZE)
6499818a481SEtienne Carriere 		panic("missing reg size property");
6509818a481SEtienne Carriere 
6519818a481SEtienne Carriere 	DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
6529818a481SEtienne Carriere 	bank->bank_id = dt_get_bank_id(fdt, node);
6539818a481SEtienne Carriere 	bank->clock = clk;
654420a32c5SEtienne Carriere 	bank->gpio_chip.ops = &stm32_gpio_ops;
655*b4893304SGatien Chevallier 	bank->sec_support = compat->secure_control;
656*b4893304SGatien Chevallier 	if (bank->sec_support)
657*b4893304SGatien Chevallier 		bank->base = io_pa_or_va_secure(&pa_va, blen);
658*b4893304SGatien Chevallier 	else
659*b4893304SGatien Chevallier 		bank->base = io_pa_or_va_nsec(&pa_va, blen);
660*b4893304SGatien Chevallier 	assert(bank->base);
6619818a481SEtienne Carriere 
6629818a481SEtienne Carriere 	/* Parse gpio-ranges with its 4 parameters */
6639818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
6649818a481SEtienne Carriere 	len /= sizeof(*cuint);
6659818a481SEtienne Carriere 	if (len % 4)
6669818a481SEtienne Carriere 		panic("wrong gpio-ranges syntax");
6679818a481SEtienne Carriere 
6689818a481SEtienne Carriere 	/* Get the last defined gpio line (offset + nb of pins) */
6699818a481SEtienne Carriere 	for (i = 0; i < len / 4; i++) {
6709818a481SEtienne Carriere 		bank->ngpios = MAX(bank->ngpios,
6719818a481SEtienne Carriere 				   (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
6729818a481SEtienne Carriere 						  fdt32_to_cpu(*(cuint + 3))));
6739818a481SEtienne Carriere 		cuint += 4;
6749818a481SEtienne Carriere 	}
6759818a481SEtienne Carriere 
676e569f6adSEtienne Carriere 	if (compat->gpioz)
677e569f6adSEtienne Carriere 		stm32mp_register_gpioz_pin_count(bank->ngpios);
678e569f6adSEtienne Carriere 
6799818a481SEtienne Carriere 	*out_bank = bank;
6809818a481SEtienne Carriere 	return TEE_SUCCESS;
6819818a481SEtienne Carriere }
6829818a481SEtienne Carriere 
683be53ee7bSEtienne Carriere static void set_bank_gpio_non_secure(struct stm32_gpio_bank *bank)
684be53ee7bSEtienne Carriere {
685be53ee7bSEtienne Carriere 	unsigned int pin = 0;
686be53ee7bSEtienne Carriere 
687580e08cfSGatien Chevallier 	for (pin = 0; pin < bank->ngpios; pin++)
688be53ee7bSEtienne Carriere 		stm32_gpio_set_secure_cfg(bank->bank_id, pin, false);
689be53ee7bSEtienne Carriere }
690be53ee7bSEtienne Carriere 
691*b4893304SGatien Chevallier /* Parse a pinctrl node to register and configure the GPIO banks it describes */
6920e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
6939818a481SEtienne Carriere 					const void *compat_data)
6949818a481SEtienne Carriere {
6959818a481SEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
6969818a481SEtienne Carriere 	const fdt32_t *cuint = NULL;
6979818a481SEtienne Carriere 	int range_offs = 0;
6989818a481SEtienne Carriere 	int b_node = 0;
6999818a481SEtienne Carriere 	int len = 0;
7009818a481SEtienne Carriere 
7019818a481SEtienne Carriere 	/* Read the ranges property (for regs memory translation) */
7029818a481SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "ranges", &len);
7039818a481SEtienne Carriere 	if (!cuint)
7049818a481SEtienne Carriere 		panic("missing ranges property");
7059818a481SEtienne Carriere 
7069818a481SEtienne Carriere 	len /= sizeof(*cuint);
7079818a481SEtienne Carriere 	if (len == 3)
7089818a481SEtienne Carriere 		range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
7099818a481SEtienne Carriere 
7109818a481SEtienne Carriere 	fdt_for_each_subnode(b_node, fdt, node) {
7119818a481SEtienne Carriere 		cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
7129818a481SEtienne Carriere 		if (cuint) {
7139818a481SEtienne Carriere 			/*
7149818a481SEtienne Carriere 			 * We found a property "gpio-controller" in the node:
7159818a481SEtienne Carriere 			 * the node is a GPIO bank description, add it to the
7169818a481SEtienne Carriere 			 * bank list.
7179818a481SEtienne Carriere 			 */
7189818a481SEtienne Carriere 			struct stm32_gpio_bank *bank = NULL;
7199818a481SEtienne Carriere 
7209818a481SEtienne Carriere 			if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
7219818a481SEtienne Carriere 			    bank_is_registered(fdt, b_node))
7229818a481SEtienne Carriere 				continue;
7239818a481SEtienne Carriere 
7249818a481SEtienne Carriere 			res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
7259818a481SEtienne Carriere 						 range_offs, &bank);
7269818a481SEtienne Carriere 			if (res)
7279818a481SEtienne Carriere 				return res;
7289818a481SEtienne Carriere 
729420a32c5SEtienne Carriere 			/* Registering a provider should not defer probe */
730420a32c5SEtienne Carriere 			res = gpio_register_provider(fdt, b_node,
731420a32c5SEtienne Carriere 						     stm32_gpio_get_dt, bank);
732420a32c5SEtienne Carriere 			if (res)
733420a32c5SEtienne Carriere 				panic();
734420a32c5SEtienne Carriere 
7359818a481SEtienne Carriere 			STAILQ_INSERT_TAIL(&bank_list, bank, link);
736be53ee7bSEtienne Carriere 
737*b4893304SGatien Chevallier 			DMSG("Registered GPIO bank %c (%d pins) @%#"PRIxVA,
738*b4893304SGatien Chevallier 			     bank->bank_id + 'A', bank->ngpios, bank->base);
739*b4893304SGatien Chevallier 
740*b4893304SGatien Chevallier 			assert(bank->ngpios <= GPIO_PIN_MAX + 1);
741*b4893304SGatien Chevallier 
742*b4893304SGatien Chevallier 			if (bank->sec_support) {
743*b4893304SGatien Chevallier 				uint32_t seccfgr = 0;
744*b4893304SGatien Chevallier 				unsigned int i = 0;
745*b4893304SGatien Chevallier 				int lenp = 0;
746*b4893304SGatien Chevallier 
747*b4893304SGatien Chevallier 				cuint = fdt_getprop(fdt, b_node, "st,protreg",
748*b4893304SGatien Chevallier 						    &lenp);
749*b4893304SGatien Chevallier 				if (!cuint) {
750be53ee7bSEtienne Carriere 					set_bank_gpio_non_secure(bank);
751*b4893304SGatien Chevallier 					continue;
752*b4893304SGatien Chevallier 				}
753*b4893304SGatien Chevallier 
754*b4893304SGatien Chevallier 				seccfgr = fdt32_to_cpu(*cuint);
755*b4893304SGatien Chevallier 				for (i = 0; i < bank->ngpios; i++)
756*b4893304SGatien Chevallier 					stm32_gpio_set_secure_cfg(bank->bank_id,
757*b4893304SGatien Chevallier 								  i,
758*b4893304SGatien Chevallier 								  seccfgr &
759*b4893304SGatien Chevallier 								  TZPROT(i));
760*b4893304SGatien Chevallier 			}
7619818a481SEtienne Carriere 		} else {
7629818a481SEtienne Carriere 			if (len != -FDT_ERR_NOTFOUND)
7639818a481SEtienne Carriere 				panic();
7649818a481SEtienne Carriere 		}
7659818a481SEtienne Carriere 	}
7669818a481SEtienne Carriere 
7679818a481SEtienne Carriere 	return TEE_SUCCESS;
7689818a481SEtienne Carriere }
7699818a481SEtienne Carriere 
770077d486eSEtienne Carriere void stm32_gpio_set_secure_cfg(unsigned int bank_id, unsigned int pin,
771077d486eSEtienne Carriere 			       bool secure)
7724b5e93edSEtienne Carriere {
773077d486eSEtienne Carriere 	struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
77498dfcedaSEtienne Carriere 	uint32_t exceptions = 0;
7754b5e93edSEtienne Carriere 
776077d486eSEtienne Carriere 	if (clk_enable(bank->clock))
777077d486eSEtienne Carriere 		panic();
77898dfcedaSEtienne Carriere 	exceptions = cpu_spin_lock_xsave(&gpio_lock);
7794b5e93edSEtienne Carriere 
7804b5e93edSEtienne Carriere 	if (secure)
781077d486eSEtienne Carriere 		io_setbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
7824b5e93edSEtienne Carriere 	else
783077d486eSEtienne Carriere 		io_clrbits32(bank->base + GPIO_SECR_OFFSET, BIT(pin));
7844b5e93edSEtienne Carriere 
785*b4893304SGatien Chevallier 	FMSG("Set secure GPIO: bank %c pin %u", bank->bank_id + 'A', pin);
786*b4893304SGatien Chevallier 
787c4cab2bbSEtienne Carriere 	cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
78898dfcedaSEtienne Carriere 	clk_disable(bank->clock);
7894b5e93edSEtienne Carriere }
7900e0435e2SEtienne Carriere 
791b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
792b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
793b38386fbSEtienne Carriere {
794b38386fbSEtienne Carriere 	struct stm32_pinctrl_array *ref = conf->priv;
795b38386fbSEtienne Carriere 	struct stm32_pinctrl *p = ref->pinctrl;
796b38386fbSEtienne Carriere 	size_t pin_count = ref->count;
797b38386fbSEtienne Carriere 	size_t n = 0;
798b38386fbSEtienne Carriere 
799b38386fbSEtienne Carriere 	for (n = 0; n < pin_count; n++)
800b38386fbSEtienne Carriere 		set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
801b38386fbSEtienne Carriere 
802b38386fbSEtienne Carriere 	return TEE_SUCCESS;
803b38386fbSEtienne Carriere }
804b38386fbSEtienne Carriere 
805b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
806b38386fbSEtienne Carriere {
807b38386fbSEtienne Carriere 	free(conf);
808b38386fbSEtienne Carriere }
809b38386fbSEtienne Carriere 
810b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
811b38386fbSEtienne Carriere 	.conf_apply = stm32_pinctrl_conf_apply,
812b38386fbSEtienne Carriere 	.conf_free = stm32_pinctrl_conf_free,
813b38386fbSEtienne Carriere };
814b38386fbSEtienne Carriere 
815b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
816b38386fbSEtienne Carriere 
81770ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
81870ac0db5SEtienne Carriere 				 unsigned int *bank, unsigned int *pin,
81970ac0db5SEtienne Carriere 				 unsigned int *count)
82070ac0db5SEtienne Carriere {
82170ac0db5SEtienne Carriere 	size_t conf_index = 0;
82270ac0db5SEtienne Carriere 	size_t pin_count = 0;
82370ac0db5SEtienne Carriere 	size_t n = 0;
82470ac0db5SEtienne Carriere 
82570ac0db5SEtienne Carriere 	assert(count);
82670ac0db5SEtienne Carriere 	if (!pinctrl)
82770ac0db5SEtienne Carriere 		goto out;
82870ac0db5SEtienne Carriere 
82970ac0db5SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
83070ac0db5SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
83170ac0db5SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
83270ac0db5SEtienne Carriere 
83370ac0db5SEtienne Carriere 		/* Consider only the stm32_gpio pins */
83470ac0db5SEtienne Carriere 		if (pinconf->ops != &stm32_pinctrl_ops)
83570ac0db5SEtienne Carriere 			continue;
83670ac0db5SEtienne Carriere 
83770ac0db5SEtienne Carriere 		if (bank || pin) {
83870ac0db5SEtienne Carriere 			for (n = 0; n < ref->count; n++) {
83970ac0db5SEtienne Carriere 				if (bank && pin_count < *count)
84070ac0db5SEtienne Carriere 					bank[pin_count] = ref->pinctrl[n].bank;
84170ac0db5SEtienne Carriere 				if (pin && pin_count < *count)
84270ac0db5SEtienne Carriere 					pin[pin_count] = ref->pinctrl[n].pin;
84370ac0db5SEtienne Carriere 				pin_count++;
84470ac0db5SEtienne Carriere 			}
84570ac0db5SEtienne Carriere 		} else {
84670ac0db5SEtienne Carriere 			pin_count += ref->count;
84770ac0db5SEtienne Carriere 		}
84870ac0db5SEtienne Carriere 	}
84970ac0db5SEtienne Carriere 
85070ac0db5SEtienne Carriere out:
85170ac0db5SEtienne Carriere 	*count = pin_count;
85270ac0db5SEtienne Carriere }
85370ac0db5SEtienne Carriere 
8547f823a77SEtienne Carriere void stm32_pinctrl_set_secure_cfg(struct pinctrl_state *pinctrl, bool secure)
8557f823a77SEtienne Carriere {
8567f823a77SEtienne Carriere 	size_t conf_index = 0;
8577f823a77SEtienne Carriere 
8587f823a77SEtienne Carriere 	if (!pinctrl)
8597f823a77SEtienne Carriere 		return;
8607f823a77SEtienne Carriere 
8617f823a77SEtienne Carriere 	for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
8627f823a77SEtienne Carriere 		struct pinconf *pinconf = pinctrl->confs[conf_index];
8637f823a77SEtienne Carriere 		struct stm32_pinctrl_array *ref = pinconf->priv;
8647f823a77SEtienne Carriere 		struct stm32_pinctrl *pc = NULL;
8657f823a77SEtienne Carriere 		size_t n = 0;
8667f823a77SEtienne Carriere 
8677f823a77SEtienne Carriere 		for (n = 0; n < ref->count; n++) {
8687f823a77SEtienne Carriere 			if (pinconf->ops != &stm32_pinctrl_ops)
8697f823a77SEtienne Carriere 				continue;
8707f823a77SEtienne Carriere 
8717f823a77SEtienne Carriere 			pc = ref->pinctrl + n;
8727f823a77SEtienne Carriere 			stm32_gpio_set_secure_cfg(pc->bank, pc->pin, secure);
8737f823a77SEtienne Carriere 		}
8747f823a77SEtienne Carriere 	}
8757f823a77SEtienne Carriere }
8767f823a77SEtienne Carriere 
877b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
878b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
879b38386fbSEtienne Carriere 				       void *data __unused,
880b38386fbSEtienne Carriere 				       struct pinconf **out_pinconf)
881b38386fbSEtienne Carriere {
882b38386fbSEtienne Carriere 	struct conf {
883b38386fbSEtienne Carriere 		struct pinconf pinconf;
884b38386fbSEtienne Carriere 		struct stm32_pinctrl_array array_ref;
885b38386fbSEtienne Carriere 	} *loc_conf = NULL;
886b38386fbSEtienne Carriere 	struct stm32_pinctrl *pinctrl = NULL;
887b38386fbSEtienne Carriere 	struct pinconf *pinconf = NULL;
888b38386fbSEtienne Carriere 	const void *fdt = NULL;
889b38386fbSEtienne Carriere 	size_t pin_count = 0;
890b38386fbSEtienne Carriere 	int pinctrl_node = 0;
891b38386fbSEtienne Carriere 	int pinmux_node = 0;
892b38386fbSEtienne Carriere 	int count = 0;
893b38386fbSEtienne Carriere 
894b38386fbSEtienne Carriere 	pinctrl_node = pargs->phandle_node;
895b38386fbSEtienne Carriere 	fdt = pargs->fdt;
896b38386fbSEtienne Carriere 	assert(fdt && pinctrl_node);
897b38386fbSEtienne Carriere 
898b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
899b38386fbSEtienne Carriere 		if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
900b38386fbSEtienne Carriere 			pin_count += (size_t)count / sizeof(uint32_t);
901b38386fbSEtienne Carriere 		else if (count != -FDT_ERR_NOTFOUND)
902b38386fbSEtienne Carriere 			panic();
903b38386fbSEtienne Carriere 	}
904b38386fbSEtienne Carriere 
905b38386fbSEtienne Carriere 	loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
906b38386fbSEtienne Carriere 	if (!loc_conf)
907b38386fbSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
908b38386fbSEtienne Carriere 
909b38386fbSEtienne Carriere 	pinconf = &loc_conf->pinconf;
910b38386fbSEtienne Carriere 	pinconf->ops = &stm32_pinctrl_ops;
911b38386fbSEtienne Carriere 	pinconf->priv = &loc_conf->array_ref;
912b38386fbSEtienne Carriere 
913b38386fbSEtienne Carriere 	loc_conf->array_ref.count = pin_count;
914b38386fbSEtienne Carriere 	pinctrl = loc_conf->array_ref.pinctrl;
915b38386fbSEtienne Carriere 
916b38386fbSEtienne Carriere 	count = 0;
917b38386fbSEtienne Carriere 	fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
918b38386fbSEtienne Carriere 		int found = 0;
919b38386fbSEtienne Carriere 
920b38386fbSEtienne Carriere 		found = get_pinctrl_from_fdt(fdt, pinmux_node, pinctrl + count,
921b38386fbSEtienne Carriere 					     pin_count - count);
922b38386fbSEtienne Carriere 		if (found <= 0 && found > ((int)pin_count - count)) {
923b38386fbSEtienne Carriere 			/* We can't recover from an error here so let's panic */
924b38386fbSEtienne Carriere 			panic();
925b38386fbSEtienne Carriere 		}
926b38386fbSEtienne Carriere 
927b38386fbSEtienne Carriere 		count += found;
928b38386fbSEtienne Carriere 	}
929b38386fbSEtienne Carriere 
930b38386fbSEtienne Carriere 	*out_pinconf = pinconf;
931b38386fbSEtienne Carriere 
932b38386fbSEtienne Carriere 	return TEE_SUCCESS;
933b38386fbSEtienne Carriere }
934b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
935b38386fbSEtienne Carriere 
9360e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
9370e0435e2SEtienne Carriere 				      const void *compat_data)
9380e0435e2SEtienne Carriere {
939b38386fbSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
940b38386fbSEtienne Carriere 
9410e0435e2SEtienne Carriere 	/* Register GPIO banks described in this pin control node */
942b38386fbSEtienne Carriere 	res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
943b38386fbSEtienne Carriere 	if (res)
944b38386fbSEtienne Carriere 		return res;
945b38386fbSEtienne Carriere 
946b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
947b38386fbSEtienne Carriere 	res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
948b38386fbSEtienne Carriere 					(void *)compat_data);
949b38386fbSEtienne Carriere 	if (res)
950b38386fbSEtienne Carriere 		return res;
951b38386fbSEtienne Carriere #endif
952b38386fbSEtienne Carriere 
953b38386fbSEtienne Carriere 	return TEE_SUCCESS;
9540e0435e2SEtienne Carriere }
9550e0435e2SEtienne Carriere 
9560e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
957e569f6adSEtienne Carriere 	{
958e569f6adSEtienne Carriere 		.compatible = "st,stm32mp135-pinctrl",
959*b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
960*b4893304SGatien Chevallier 			.secure_control = true,
961*b4893304SGatien Chevallier 		},
962e569f6adSEtienne Carriere 	},
963e569f6adSEtienne Carriere 	{
964e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-pinctrl",
965*b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
966*b4893304SGatien Chevallier 			.secure_control = false,
967*b4893304SGatien Chevallier 		},
968e569f6adSEtienne Carriere 	},
969e569f6adSEtienne Carriere 	{
970e569f6adSEtienne Carriere 		.compatible = "st,stm32mp157-z-pinctrl",
971*b4893304SGatien Chevallier 		.compat_data = &(struct bank_compat){
972*b4893304SGatien Chevallier 			.gpioz = true,
973*b4893304SGatien Chevallier 			.secure_control = true,
974*b4893304SGatien Chevallier 		},
975e569f6adSEtienne Carriere 	},
9760e0435e2SEtienne Carriere 	{ }
9770e0435e2SEtienne Carriere };
9780e0435e2SEtienne Carriere 
9790e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
9800e0435e2SEtienne Carriere 	.name = "stm32_gpio-pinctrl",
9810e0435e2SEtienne Carriere 	.type = DT_DRIVER_PINCTRL,
9820e0435e2SEtienne Carriere 	.match_table = stm32_pinctrl_match_table,
9830e0435e2SEtienne Carriere 	.probe = stm32_pinctrl_probe,
9840e0435e2SEtienne Carriere };
985