14b5e93edSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
24b5e93edSEtienne Carriere /*
3bd03c8c3SGatien Chevallier * Copyright (c) 2017-2024, STMicroelectronics
44b5e93edSEtienne Carriere *
54b5e93edSEtienne Carriere * STM32 GPIO driver is used as pin controller for stm32mp SoCs.
64b5e93edSEtienne Carriere */
74b5e93edSEtienne Carriere
84b5e93edSEtienne Carriere #include <assert.h>
969715ce9SEtienne Carriere #include <compiler.h>
1097391ffbSEtienne Carriere #include <drivers/clk.h>
1197391ffbSEtienne Carriere #include <drivers/clk_dt.h>
12a650c9cbSEtienne Carriere #include <drivers/firewall.h>
13420a32c5SEtienne Carriere #include <drivers/gpio.h>
14b38386fbSEtienne Carriere #include <drivers/pinctrl.h>
154b5e93edSEtienne Carriere #include <drivers/stm32_gpio.h>
16bd03c8c3SGatien Chevallier #include <drivers/stm32_rif.h>
17a650c9cbSEtienne Carriere #include <dt-bindings/gpio/stm32mp_gpio.h>
185f27da69SEtienne Carriere #include <dt-bindings/pinctrl/stm32-pinfunc.h>
194b5e93edSEtienne Carriere #include <io.h>
204b5e93edSEtienne Carriere #include <kernel/dt.h>
2165401337SJens Wiklander #include <kernel/boot.h>
224b5e93edSEtienne Carriere #include <kernel/panic.h>
23bfc43b68SGatien Chevallier #include <kernel/pm.h>
244b5e93edSEtienne Carriere #include <kernel/spinlock.h>
25a2fc83d1SJerome Forissier #include <libfdt.h>
264b5e93edSEtienne Carriere #include <mm/core_memprot.h>
274b5e93edSEtienne Carriere #include <stdbool.h>
2869715ce9SEtienne Carriere #include <stdint.h>
294b5e93edSEtienne Carriere #include <stm32_util.h>
309818a481SEtienne Carriere #include <sys/queue.h>
314b5e93edSEtienne Carriere #include <trace.h>
324b5e93edSEtienne Carriere #include <util.h>
334b5e93edSEtienne Carriere
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)
46bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_OFFSET U(0x34)
47bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_OFFSET U(0x38)
48bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR(x) (U(0x50) + U(0x8) * (x))
49bd03c8c3SGatien Chevallier #define GPIO_SEMCR(x) (U(0x54) + U(0x8) * (x))
504b5e93edSEtienne Carriere
515eed568cSGatien Chevallier #define GPIO_ALT_LOWER_LIMIT U(0x8)
524b5e93edSEtienne Carriere
53bd03c8c3SGatien Chevallier /*
54bd03c8c3SGatien Chevallier * CIDCFGR register bitfields
55bd03c8c3SGatien Chevallier */
56bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SEMWL_MASK GENMASK_32(23, 16)
57bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_SCID_MASK GENMASK_32(6, 4)
58bd03c8c3SGatien Chevallier #define GPIO_CIDCFGR_CONF_MASK (_CIDCFGR_CFEN | _CIDCFGR_SEMEN | \
59bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SCID_MASK | \
60bd03c8c3SGatien Chevallier GPIO_CIDCFGR_SEMWL_MASK)
61bd03c8c3SGatien Chevallier
62bd03c8c3SGatien Chevallier /*
63bd03c8c3SGatien Chevallier * PRIVCFGR register bitfields
64bd03c8c3SGatien Chevallier */
65bd03c8c3SGatien Chevallier #define GPIO_PRIVCFGR_MASK GENMASK_32(15, 0)
66bd03c8c3SGatien Chevallier
67bd03c8c3SGatien Chevallier /*
68bd03c8c3SGatien Chevallier * SECCFGR register bitfields
69bd03c8c3SGatien Chevallier */
70bd03c8c3SGatien Chevallier #define GPIO_SECCFGR_MASK GENMASK_32(15, 0)
71bd03c8c3SGatien Chevallier
72bd03c8c3SGatien Chevallier /*
73bd03c8c3SGatien Chevallier * RCFGLOCKR register bitfields
74bd03c8c3SGatien Chevallier */
75bd03c8c3SGatien Chevallier #define GPIO_RCFGLOCKR_MASK GENMASK_32(15, 0)
76bd03c8c3SGatien Chevallier
77bd03c8c3SGatien Chevallier /*
78bd03c8c3SGatien Chevallier * SEMCR register bitfields
79bd03c8c3SGatien Chevallier */
80bd03c8c3SGatien Chevallier #define GPIO_SEMCR_SCID_M GENMASK_32(6, 4)
81bd03c8c3SGatien Chevallier
824b5e93edSEtienne Carriere #define GPIO_MODE_MASK GENMASK_32(1, 0)
834b5e93edSEtienne Carriere #define GPIO_OSPEED_MASK GENMASK_32(1, 0)
844b5e93edSEtienne Carriere #define GPIO_PUPD_PULL_MASK GENMASK_32(1, 0)
85729093d5SLionel Debieve #define GPIO_ALTERNATE_MASK GENMASK_32(3, 0)
864b5e93edSEtienne Carriere
875eed568cSGatien Chevallier #define DT_GPIO_BANK_SHIFT U(12)
884b5e93edSEtienne Carriere #define DT_GPIO_BANK_MASK GENMASK_32(16, 12)
895eed568cSGatien Chevallier #define DT_GPIO_PIN_SHIFT U(8)
904b5e93edSEtienne Carriere #define DT_GPIO_PIN_MASK GENMASK_32(11, 8)
914b5e93edSEtienne Carriere #define DT_GPIO_MODE_MASK GENMASK_32(7, 0)
924b5e93edSEtienne Carriere
939818a481SEtienne Carriere #define DT_GPIO_BANK_NAME0 "GPIOA"
949818a481SEtienne Carriere
9569715ce9SEtienne Carriere #define GPIO_MODE_INPUT U(0x0)
9669715ce9SEtienne Carriere #define GPIO_MODE_OUTPUT U(0x1)
9769715ce9SEtienne Carriere #define GPIO_MODE_ALTERNATE U(0x2)
9869715ce9SEtienne Carriere #define GPIO_MODE_ANALOG U(0x3)
9969715ce9SEtienne Carriere
10069715ce9SEtienne Carriere #define GPIO_OTYPE_PUSH_PULL U(0x0)
10169715ce9SEtienne Carriere #define GPIO_OTYPE_OPEN_DRAIN U(0x1)
10269715ce9SEtienne Carriere
10369715ce9SEtienne Carriere #define GPIO_OSPEED_LOW U(0x0)
10469715ce9SEtienne Carriere #define GPIO_OSPEED_MEDIUM U(0x1)
10569715ce9SEtienne Carriere #define GPIO_OSPEED_HIGH U(0x2)
10669715ce9SEtienne Carriere #define GPIO_OSPEED_VERY_HIGH U(0x3)
10769715ce9SEtienne Carriere
10869715ce9SEtienne Carriere #define GPIO_PUPD_NO_PULL U(0x0)
10969715ce9SEtienne Carriere #define GPIO_PUPD_PULL_UP U(0x1)
11069715ce9SEtienne Carriere #define GPIO_PUPD_PULL_DOWN U(0x2)
11169715ce9SEtienne Carriere
11269715ce9SEtienne Carriere #define GPIO_OD_LEVEL_LOW U(0x0)
11369715ce9SEtienne Carriere #define GPIO_OD_LEVEL_HIGH U(0x1)
11469715ce9SEtienne Carriere
115bd03c8c3SGatien Chevallier #define GPIO_MAX_CID_SUPPORTED U(3)
116bd03c8c3SGatien Chevallier
11769715ce9SEtienne Carriere /*
11869715ce9SEtienne Carriere * GPIO configuration description structured as single 16bit word
11969715ce9SEtienne Carriere * for efficient save/restore when GPIO pin suspends or resumes.
12069715ce9SEtienne Carriere *
12169715ce9SEtienne Carriere * @mode: One of GPIO_MODE_*
12269715ce9SEtienne Carriere * @otype: One of GPIO_OTYPE_*
12369715ce9SEtienne Carriere * @ospeed: One of GPIO_OSPEED_*
12469715ce9SEtienne Carriere * @pupd: One of GPIO_PUPD_*
12569715ce9SEtienne Carriere * @od: One of GPIO_OD_*
12669715ce9SEtienne Carriere * @af: Alternate function numerical ID between 0 and 15
1275f27da69SEtienne Carriere * @nsec: Hint on expected secure state of the pin: 0 if secure, 1 otherwise
12869715ce9SEtienne Carriere */
12969715ce9SEtienne Carriere struct gpio_cfg {
13069715ce9SEtienne Carriere uint16_t mode: 2;
13169715ce9SEtienne Carriere uint16_t otype: 1;
13269715ce9SEtienne Carriere uint16_t ospeed: 2;
13369715ce9SEtienne Carriere uint16_t pupd: 2;
13469715ce9SEtienne Carriere uint16_t od: 1;
13569715ce9SEtienne Carriere uint16_t af: 4;
1365f27da69SEtienne Carriere uint16_t nsec: 1;
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
gpio_chip_to_bank(struct gpio_chip * chip)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
stm32_gpio_chip_bank_id(struct gpio_chip * chip)23261bf256aSGatien Chevallier unsigned int stm32_gpio_chip_bank_id(struct gpio_chip *chip)
23361bf256aSGatien Chevallier {
23461bf256aSGatien Chevallier struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
23561bf256aSGatien Chevallier
23661bf256aSGatien Chevallier return bank->bank_id;
23761bf256aSGatien Chevallier }
23861bf256aSGatien Chevallier
stm32_gpio_get_level(struct gpio_chip * chip,unsigned int gpio_pin)239420a32c5SEtienne Carriere static enum gpio_level stm32_gpio_get_level(struct gpio_chip *chip,
240420a32c5SEtienne Carriere unsigned int gpio_pin)
241420a32c5SEtienne Carriere {
242420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
243420a32c5SEtienne Carriere enum gpio_level level = GPIO_LEVEL_HIGH;
244420a32c5SEtienne Carriere unsigned int reg_offset = 0;
245420a32c5SEtienne Carriere unsigned int mode = 0;
246420a32c5SEtienne Carriere
247420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios);
2482fd102ebSEtienne Carriere
2492fd102ebSEtienne Carriere if (clk_enable(bank->clock))
2502fd102ebSEtienne Carriere panic();
251420a32c5SEtienne Carriere
252420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
253420a32c5SEtienne Carriere GPIO_MODE_MASK;
254420a32c5SEtienne Carriere
255420a32c5SEtienne Carriere switch (mode) {
256420a32c5SEtienne Carriere case GPIO_MODE_INPUT:
257420a32c5SEtienne Carriere reg_offset = GPIO_IDR_OFFSET;
258420a32c5SEtienne Carriere break;
259420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT:
260420a32c5SEtienne Carriere reg_offset = GPIO_ODR_OFFSET;
261420a32c5SEtienne Carriere break;
262420a32c5SEtienne Carriere default:
263420a32c5SEtienne Carriere panic();
264420a32c5SEtienne Carriere }
265420a32c5SEtienne Carriere
266420a32c5SEtienne Carriere if (io_read32(bank->base + reg_offset) & BIT(gpio_pin))
267420a32c5SEtienne Carriere level = GPIO_LEVEL_HIGH;
268420a32c5SEtienne Carriere else
269420a32c5SEtienne Carriere level = GPIO_LEVEL_LOW;
270420a32c5SEtienne Carriere
271420a32c5SEtienne Carriere clk_disable(bank->clock);
272420a32c5SEtienne Carriere
273420a32c5SEtienne Carriere return level;
274420a32c5SEtienne Carriere }
275420a32c5SEtienne Carriere
stm32_gpio_set_level(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_level level)276420a32c5SEtienne Carriere static void stm32_gpio_set_level(struct gpio_chip *chip, unsigned int gpio_pin,
277420a32c5SEtienne Carriere enum gpio_level level)
278420a32c5SEtienne Carriere {
279420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
280420a32c5SEtienne Carriere
281420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios);
2822fd102ebSEtienne Carriere
2832fd102ebSEtienne Carriere if (clk_enable(bank->clock))
2842fd102ebSEtienne Carriere panic();
285420a32c5SEtienne Carriere
286420a32c5SEtienne Carriere if (level == GPIO_LEVEL_HIGH)
287420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin));
288420a32c5SEtienne Carriere else
289420a32c5SEtienne Carriere io_write32(bank->base + GPIO_BSRR_OFFSET, BIT(gpio_pin + 16));
290420a32c5SEtienne Carriere
291420a32c5SEtienne Carriere clk_disable(bank->clock);
292420a32c5SEtienne Carriere }
293420a32c5SEtienne Carriere
stm32_gpio_get_direction(struct gpio_chip * chip,unsigned int gpio_pin)294420a32c5SEtienne Carriere static enum gpio_dir stm32_gpio_get_direction(struct gpio_chip *chip,
295420a32c5SEtienne Carriere unsigned int gpio_pin)
296420a32c5SEtienne Carriere {
297420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
298420a32c5SEtienne Carriere uint32_t mode = 0;
299420a32c5SEtienne Carriere
300420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios);
3012fd102ebSEtienne Carriere
3022fd102ebSEtienne Carriere if (clk_enable(bank->clock))
3032fd102ebSEtienne Carriere panic();
304420a32c5SEtienne Carriere
305420a32c5SEtienne Carriere mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (gpio_pin << 1)) &
306420a32c5SEtienne Carriere GPIO_MODE_MASK;
307420a32c5SEtienne Carriere
308420a32c5SEtienne Carriere clk_disable(bank->clock);
309420a32c5SEtienne Carriere
310420a32c5SEtienne Carriere switch (mode) {
311420a32c5SEtienne Carriere case GPIO_MODE_INPUT:
312420a32c5SEtienne Carriere return GPIO_DIR_IN;
313420a32c5SEtienne Carriere case GPIO_MODE_OUTPUT:
314420a32c5SEtienne Carriere return GPIO_DIR_OUT;
315420a32c5SEtienne Carriere default:
316420a32c5SEtienne Carriere panic();
317420a32c5SEtienne Carriere }
318420a32c5SEtienne Carriere }
319420a32c5SEtienne Carriere
stm32_gpio_set_direction(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_dir direction)320420a32c5SEtienne Carriere static void stm32_gpio_set_direction(struct gpio_chip *chip,
321420a32c5SEtienne Carriere unsigned int gpio_pin,
322420a32c5SEtienne Carriere enum gpio_dir direction)
323420a32c5SEtienne Carriere {
324420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
325420a32c5SEtienne Carriere uint32_t exceptions = 0;
326420a32c5SEtienne Carriere uint32_t mode = 0;
327420a32c5SEtienne Carriere
328420a32c5SEtienne Carriere assert(gpio_pin < bank->ngpios);
329420a32c5SEtienne Carriere
330420a32c5SEtienne Carriere if (direction == GPIO_DIR_IN)
331420a32c5SEtienne Carriere mode = GPIO_MODE_INPUT;
332420a32c5SEtienne Carriere else
333420a32c5SEtienne Carriere mode = GPIO_MODE_OUTPUT;
334420a32c5SEtienne Carriere
3352fd102ebSEtienne Carriere if (clk_enable(bank->clock))
3362fd102ebSEtienne Carriere panic();
337420a32c5SEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock);
338420a32c5SEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
339420a32c5SEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, gpio_pin << 1),
340420a32c5SEtienne Carriere SHIFT_U32(mode, gpio_pin << 1));
341420a32c5SEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
342420a32c5SEtienne Carriere clk_disable(bank->clock);
343420a32c5SEtienne Carriere }
344420a32c5SEtienne Carriere
345bfc43b68SGatien Chevallier /* Forward reference to the PM callback handler for consumed GPIOs */
346bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op, unsigned int pm_hint,
347bfc43b68SGatien Chevallier const struct pm_callback_handle *pm_hdl);
348bfc43b68SGatien Chevallier
349430c415aSEtienne Carriere /* Forward reference to RIF semaphore release helper function */
350430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank,
351430c415aSEtienne Carriere unsigned int pin);
352430c415aSEtienne Carriere
stm32_gpio_configure(struct gpio_chip * chip,struct gpio * gpio)353*3f8e5418SPatrick Delaunay static TEE_Result stm32_gpio_configure(struct gpio_chip *chip,
354*3f8e5418SPatrick Delaunay struct gpio *gpio)
355*3f8e5418SPatrick Delaunay {
356*3f8e5418SPatrick Delaunay struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
357*3f8e5418SPatrick Delaunay uint32_t exceptions = 0;
358*3f8e5418SPatrick Delaunay uint32_t otype = 0;
359*3f8e5418SPatrick Delaunay uint32_t pupd = 0;
360*3f8e5418SPatrick Delaunay unsigned int shift_1b = gpio->pin;
361*3f8e5418SPatrick Delaunay unsigned int shift_2b = SHIFT_U32(gpio->pin, 1);
362*3f8e5418SPatrick Delaunay
363*3f8e5418SPatrick Delaunay assert(is_stm32_gpio_chip(chip));
364*3f8e5418SPatrick Delaunay
365*3f8e5418SPatrick Delaunay if (gpio->dt_flags & GPIO_PULL_UP)
366*3f8e5418SPatrick Delaunay pupd = GPIO_PUPD_PULL_UP;
367*3f8e5418SPatrick Delaunay else if (gpio->dt_flags & GPIO_PULL_DOWN)
368*3f8e5418SPatrick Delaunay pupd = GPIO_PUPD_PULL_DOWN;
369*3f8e5418SPatrick Delaunay else
370*3f8e5418SPatrick Delaunay pupd = GPIO_PUPD_NO_PULL;
371*3f8e5418SPatrick Delaunay
372*3f8e5418SPatrick Delaunay if (gpio->dt_flags & GPIO_LINE_OPEN_DRAIN)
373*3f8e5418SPatrick Delaunay otype = GPIO_OTYPE_OPEN_DRAIN;
374*3f8e5418SPatrick Delaunay else
375*3f8e5418SPatrick Delaunay otype = GPIO_OTYPE_PUSH_PULL;
376*3f8e5418SPatrick Delaunay
377*3f8e5418SPatrick Delaunay if (clk_enable(bank->clock))
378*3f8e5418SPatrick Delaunay panic();
379*3f8e5418SPatrick Delaunay exceptions = cpu_spin_lock_xsave(&gpio_lock);
380*3f8e5418SPatrick Delaunay
381*3f8e5418SPatrick Delaunay io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET,
382*3f8e5418SPatrick Delaunay SHIFT_U32(GPIO_OTYPE_OPEN_DRAIN, shift_1b),
383*3f8e5418SPatrick Delaunay SHIFT_U32(otype, shift_1b));
384*3f8e5418SPatrick Delaunay
385*3f8e5418SPatrick Delaunay io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET,
386*3f8e5418SPatrick Delaunay SHIFT_U32(GPIO_PUPD_PULL_MASK, shift_2b),
387*3f8e5418SPatrick Delaunay SHIFT_U32(pupd, shift_2b));
388*3f8e5418SPatrick Delaunay
389*3f8e5418SPatrick Delaunay cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
390*3f8e5418SPatrick Delaunay clk_disable(bank->clock);
391*3f8e5418SPatrick Delaunay
392*3f8e5418SPatrick Delaunay return TEE_SUCCESS;
393*3f8e5418SPatrick Delaunay }
394*3f8e5418SPatrick Delaunay
stm32_gpio_put_gpio(struct gpio_chip * chip,struct gpio * gpio)395bfc43b68SGatien Chevallier static void stm32_gpio_put_gpio(struct gpio_chip *chip, struct gpio *gpio)
396420a32c5SEtienne Carriere {
397bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
398bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *tstate = NULL;
399bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *state = NULL;
400bfc43b68SGatien Chevallier uint32_t exceptions = 0;
401bfc43b68SGatien Chevallier
402420a32c5SEtienne Carriere assert(is_stm32_gpio_chip(chip));
403bfc43b68SGatien Chevallier
404bfc43b68SGatien Chevallier exceptions = cpu_spin_lock_xsave(&gpio_lock);
405bfc43b68SGatien Chevallier
406bfc43b68SGatien Chevallier SLIST_FOREACH_SAFE(state, &consumed_gpios_head, link, tstate) {
407bfc43b68SGatien Chevallier if (state->gpio_pinctrl.bank == bank->bank_id &&
408bfc43b68SGatien Chevallier state->gpio_pinctrl.pin == gpio->pin) {
409bfc43b68SGatien Chevallier SLIST_REMOVE(&consumed_gpios_head, state,
410bfc43b68SGatien Chevallier stm32_gpio_pm_state, link);
411bfc43b68SGatien Chevallier unregister_pm_driver_cb(consumed_gpios_pm, state);
412430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, gpio->pin);
413bfc43b68SGatien Chevallier free(state);
414420a32c5SEtienne Carriere free(gpio);
415bfc43b68SGatien Chevallier break;
416bfc43b68SGatien Chevallier }
417bfc43b68SGatien Chevallier }
418bfc43b68SGatien Chevallier assert(state);
419bfc43b68SGatien Chevallier
420bfc43b68SGatien Chevallier cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
421420a32c5SEtienne Carriere }
422420a32c5SEtienne Carriere
423420a32c5SEtienne Carriere static const struct gpio_ops stm32_gpio_ops = {
424420a32c5SEtienne Carriere .get_direction = stm32_gpio_get_direction,
425420a32c5SEtienne Carriere .set_direction = stm32_gpio_set_direction,
426420a32c5SEtienne Carriere .get_value = stm32_gpio_get_level,
427420a32c5SEtienne Carriere .set_value = stm32_gpio_set_level,
428*3f8e5418SPatrick Delaunay .configure = stm32_gpio_configure,
429420a32c5SEtienne Carriere .put = stm32_gpio_put_gpio,
430420a32c5SEtienne Carriere };
431420a32c5SEtienne Carriere
is_stm32_gpio_chip(struct gpio_chip * chip)432420a32c5SEtienne Carriere static bool __maybe_unused is_stm32_gpio_chip(struct gpio_chip *chip)
433420a32c5SEtienne Carriere {
434420a32c5SEtienne Carriere return chip && chip->ops == &stm32_gpio_ops;
435420a32c5SEtienne Carriere }
436420a32c5SEtienne Carriere
stm32_gpio_get_bank(unsigned int bank_id)437077d486eSEtienne Carriere static struct stm32_gpio_bank *stm32_gpio_get_bank(unsigned int bank_id)
4384b5e93edSEtienne Carriere {
439077d486eSEtienne Carriere struct stm32_gpio_bank *bank = NULL;
4404b5e93edSEtienne Carriere
441077d486eSEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link)
442077d486eSEtienne Carriere if (bank_id == bank->bank_id)
443077d486eSEtienne Carriere return bank;
444077d486eSEtienne Carriere
445077d486eSEtienne Carriere panic();
446077d486eSEtienne Carriere }
447077d486eSEtienne Carriere
448430c415aSEtienne Carriere #if defined(CFG_STM32_RIF)
pin_is_accessible(struct stm32_gpio_bank * bank,unsigned int pin)4494675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank, unsigned int pin)
4504675225eSEtienne Carriere {
4514675225eSEtienne Carriere bool accessible = false;
4524675225eSEtienne Carriere uint32_t cidcfgr = 0;
4534675225eSEtienne Carriere
4544675225eSEtienne Carriere if (!bank->rif_cfg)
4554675225eSEtienne Carriere return true;
4564675225eSEtienne Carriere
4574675225eSEtienne Carriere if (clk_enable(bank->clock))
4584675225eSEtienne Carriere panic();
4594675225eSEtienne Carriere
4604675225eSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin));
4614675225eSEtienne Carriere
4624675225eSEtienne Carriere if (!(cidcfgr & _CIDCFGR_CFEN)) {
4634675225eSEtienne Carriere /* Resource can be accessed when CID filtering is disabled */
4644675225eSEtienne Carriere accessible = true;
4654675225eSEtienne Carriere } else if (stm32_rif_scid_ok(cidcfgr, GPIO_CIDCFGR_SCID_MASK,
4664675225eSEtienne Carriere RIF_CID1)) {
4674675225eSEtienne Carriere /* Resource can be accessed if CID1 is statically allowed */
4684675225eSEtienne Carriere accessible = true;
4694675225eSEtienne Carriere } else if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) {
4704675225eSEtienne Carriere /* CID1 is allowed to request the semaphore */
4714675225eSEtienne Carriere accessible = true;
4724675225eSEtienne Carriere }
4734675225eSEtienne Carriere
4744675225eSEtienne Carriere clk_disable(bank->clock);
4754675225eSEtienne Carriere
4764675225eSEtienne Carriere return accessible;
4774675225eSEtienne Carriere }
4784675225eSEtienne Carriere
acquire_rif_semaphore_if_needed(struct stm32_gpio_bank * bank,unsigned int pin)479430c415aSEtienne Carriere static TEE_Result acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank,
480430c415aSEtienne Carriere unsigned int pin)
481430c415aSEtienne Carriere {
482430c415aSEtienne Carriere TEE_Result res = TEE_SUCCESS;
483430c415aSEtienne Carriere uint32_t cidcfgr = 0;
484430c415aSEtienne Carriere
485430c415aSEtienne Carriere if (!bank->rif_cfg)
486430c415aSEtienne Carriere return TEE_SUCCESS;
487430c415aSEtienne Carriere
488430c415aSEtienne Carriere res = clk_enable(bank->clock);
489430c415aSEtienne Carriere if (res)
490430c415aSEtienne Carriere return res;
491430c415aSEtienne Carriere
492430c415aSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin));
493430c415aSEtienne Carriere
494430c415aSEtienne Carriere if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
495430c415aSEtienne Carriere res = stm32_rif_acquire_semaphore(bank->base + GPIO_SEMCR(pin),
496430c415aSEtienne Carriere GPIO_MAX_CID_SUPPORTED);
497430c415aSEtienne Carriere
498430c415aSEtienne Carriere clk_disable(bank->clock);
499430c415aSEtienne Carriere
500430c415aSEtienne Carriere return res;
501430c415aSEtienne Carriere }
502430c415aSEtienne Carriere
semaphore_current_cid(struct stm32_gpio_bank * bank,unsigned int pin)503430c415aSEtienne Carriere static uint32_t semaphore_current_cid(struct stm32_gpio_bank *bank,
504430c415aSEtienne Carriere unsigned int pin)
505430c415aSEtienne Carriere {
506430c415aSEtienne Carriere return (io_read32(bank->base + GPIO_SEMCR(pin)) >>
507430c415aSEtienne Carriere _CIDCFGR_SCID_SHIFT) &
508430c415aSEtienne Carriere GENMASK_32(GPIO_MAX_CID_SUPPORTED - 1, 0);
509430c415aSEtienne Carriere }
510430c415aSEtienne Carriere
release_rif_semaphore_if_acquired(struct stm32_gpio_bank * bank,unsigned int pin)511430c415aSEtienne Carriere static void release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank,
512430c415aSEtienne Carriere unsigned int pin)
513430c415aSEtienne Carriere {
514430c415aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC;
515430c415aSEtienne Carriere uint32_t cidcfgr = 0;
516430c415aSEtienne Carriere
517430c415aSEtienne Carriere if (!bank->rif_cfg)
518430c415aSEtienne Carriere return;
519430c415aSEtienne Carriere
520430c415aSEtienne Carriere res = clk_enable(bank->clock);
521430c415aSEtienne Carriere if (res)
522430c415aSEtienne Carriere panic();
523430c415aSEtienne Carriere
524430c415aSEtienne Carriere cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(pin));
525430c415aSEtienne Carriere
526430c415aSEtienne Carriere if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1) &&
527430c415aSEtienne Carriere semaphore_current_cid(bank, pin) == RIF_CID1) {
528430c415aSEtienne Carriere res = stm32_rif_release_semaphore(bank->base + GPIO_SEMCR(pin),
529430c415aSEtienne Carriere GPIO_MAX_CID_SUPPORTED);
530430c415aSEtienne Carriere if (res) {
531430c415aSEtienne Carriere EMSG("Failed to release GPIO %c%u semaphore",
532430c415aSEtienne Carriere bank->bank_id + 'A', pin);
533430c415aSEtienne Carriere panic();
534430c415aSEtienne Carriere }
535430c415aSEtienne Carriere }
536430c415aSEtienne Carriere
537430c415aSEtienne Carriere clk_disable(bank->clock);
538430c415aSEtienne Carriere }
539430c415aSEtienne Carriere #else
pin_is_accessible(struct stm32_gpio_bank * bank __unused,unsigned int pin __unused)5404675225eSEtienne Carriere static bool pin_is_accessible(struct stm32_gpio_bank *bank __unused,
5414675225eSEtienne Carriere unsigned int pin __unused)
5424675225eSEtienne Carriere {
5434675225eSEtienne Carriere return true;
5444675225eSEtienne Carriere }
5454675225eSEtienne Carriere
546430c415aSEtienne Carriere static TEE_Result
acquire_rif_semaphore_if_needed(struct stm32_gpio_bank * bank __unused,unsigned int pin __unused)547430c415aSEtienne Carriere acquire_rif_semaphore_if_needed(struct stm32_gpio_bank *bank __unused,
548430c415aSEtienne Carriere unsigned int pin __unused)
549430c415aSEtienne Carriere {
550430c415aSEtienne Carriere return TEE_SUCCESS;
551430c415aSEtienne Carriere }
552430c415aSEtienne Carriere
553430c415aSEtienne Carriere static void
release_rif_semaphore_if_acquired(struct stm32_gpio_bank * bank __unused,unsigned int pin __unused)554430c415aSEtienne Carriere release_rif_semaphore_if_acquired(struct stm32_gpio_bank *bank __unused,
555430c415aSEtienne Carriere unsigned int pin __unused)
556430c415aSEtienne Carriere {
557430c415aSEtienne Carriere }
558430c415aSEtienne Carriere #endif /*CFG_STM32_RIF*/
559430c415aSEtienne Carriere
pin_is_secure(struct stm32_gpio_bank * bank,unsigned int pin)5604675225eSEtienne Carriere static bool pin_is_secure(struct stm32_gpio_bank *bank, unsigned int pin)
5614675225eSEtienne Carriere {
5624675225eSEtienne Carriere bool secure = false;
5634675225eSEtienne Carriere
5644675225eSEtienne Carriere if (bank->rif_cfg || bank->sec_support) {
5654675225eSEtienne Carriere if (clk_enable(bank->clock))
5664675225eSEtienne Carriere panic();
5674675225eSEtienne Carriere
5684675225eSEtienne Carriere secure = io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(pin);
5694675225eSEtienne Carriere
5704675225eSEtienne Carriere clk_disable(bank->clock);
5714675225eSEtienne Carriere }
5724675225eSEtienne Carriere
5734675225eSEtienne Carriere return secure;
5744675225eSEtienne Carriere }
5754675225eSEtienne Carriere
576077d486eSEtienne Carriere /* Save to output @cfg the current GPIO (@bank_id/@pin) configuration */
get_gpio_cfg(uint32_t bank_id,uint32_t pin,struct gpio_cfg * cfg)577bfc43b68SGatien Chevallier static void get_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
578077d486eSEtienne Carriere {
579077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
580077d486eSEtienne Carriere
581077d486eSEtienne Carriere if (clk_enable(bank->clock))
582077d486eSEtienne Carriere panic();
5834b5e93edSEtienne Carriere
5844b5e93edSEtienne Carriere /*
5854b5e93edSEtienne Carriere * Save GPIO configuration bits spread over the few bank registers.
5864b5e93edSEtienne Carriere * 1bit fields are accessed at bit position being the pin index.
5874b5e93edSEtienne Carriere * 2bit fields are accessed at bit position being twice the pin index.
5884b5e93edSEtienne Carriere * 4bit fields are accessed at bit position being fourth the pin index
5894b5e93edSEtienne Carriere * but accessed from 2 32bit registers at incremental addresses.
5904b5e93edSEtienne Carriere */
591077d486eSEtienne Carriere cfg->mode = (io_read32(bank->base + GPIO_MODER_OFFSET) >> (pin << 1)) &
5924b5e93edSEtienne Carriere GPIO_MODE_MASK;
5934b5e93edSEtienne Carriere
594077d486eSEtienne Carriere cfg->otype = (io_read32(bank->base + GPIO_OTYPER_OFFSET) >> pin) & 1;
5954b5e93edSEtienne Carriere
596077d486eSEtienne Carriere cfg->ospeed = (io_read32(bank->base + GPIO_OSPEEDR_OFFSET) >>
597077d486eSEtienne Carriere (pin << 1)) & GPIO_OSPEED_MASK;
5984b5e93edSEtienne Carriere
599077d486eSEtienne Carriere cfg->pupd = (io_read32(bank->base + GPIO_PUPDR_OFFSET) >> (pin << 1)) &
6004b5e93edSEtienne Carriere GPIO_PUPD_PULL_MASK;
6014b5e93edSEtienne Carriere
602077d486eSEtienne Carriere cfg->od = (io_read32(bank->base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1;
6034b5e93edSEtienne Carriere
6044b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT)
605077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRL_OFFSET) >>
606077d486eSEtienne Carriere (pin << 2)) & GPIO_ALTERNATE_MASK;
6074b5e93edSEtienne Carriere else
608077d486eSEtienne Carriere cfg->af = (io_read32(bank->base + GPIO_AFRH_OFFSET) >>
6094b5e93edSEtienne Carriere ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) &
6104b5e93edSEtienne Carriere GPIO_ALTERNATE_MASK;
6114b5e93edSEtienne Carriere
612077d486eSEtienne Carriere clk_disable(bank->clock);
6134b5e93edSEtienne Carriere }
6144b5e93edSEtienne Carriere
6154b5e93edSEtienne Carriere /* Apply GPIO (@bank/@pin) configuration described by @cfg */
set_gpio_cfg(uint32_t bank_id,uint32_t pin,struct gpio_cfg * cfg)616077d486eSEtienne Carriere static void set_gpio_cfg(uint32_t bank_id, uint32_t pin, struct gpio_cfg *cfg)
6174b5e93edSEtienne Carriere {
618077d486eSEtienne Carriere struct stm32_gpio_bank *bank = stm32_gpio_get_bank(bank_id);
61998dfcedaSEtienne Carriere uint32_t exceptions = 0;
6204b5e93edSEtienne Carriere
621077d486eSEtienne Carriere if (clk_enable(bank->clock))
622077d486eSEtienne Carriere panic();
62398dfcedaSEtienne Carriere exceptions = cpu_spin_lock_xsave(&gpio_lock);
6244b5e93edSEtienne Carriere
6254b5e93edSEtienne Carriere /* Load GPIO MODE value, 2bit value shifted by twice the pin number */
626077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_MODER_OFFSET,
627bed4582fSEtienne Carriere SHIFT_U32(GPIO_MODE_MASK, pin << 1),
628bed4582fSEtienne Carriere SHIFT_U32(cfg->mode, pin << 1));
6294b5e93edSEtienne Carriere
6304b5e93edSEtienne Carriere /* Load GPIO Output TYPE value, 1bit shifted by pin number value */
631077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OTYPER_OFFSET, BIT(pin),
632bed4582fSEtienne Carriere SHIFT_U32(cfg->otype, pin));
6334b5e93edSEtienne Carriere
6344b5e93edSEtienne Carriere /* Load GPIO Output Speed confguration, 2bit value */
635077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_OSPEEDR_OFFSET,
636bed4582fSEtienne Carriere SHIFT_U32(GPIO_OSPEED_MASK, pin << 1),
637bed4582fSEtienne Carriere SHIFT_U32(cfg->ospeed, pin << 1));
6384b5e93edSEtienne Carriere
6394b5e93edSEtienne Carriere /* Load GPIO pull configuration, 2bit value */
640077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_PUPDR_OFFSET, BIT(pin),
641bed4582fSEtienne Carriere SHIFT_U32(cfg->pupd, pin << 1));
6424b5e93edSEtienne Carriere
6434b5e93edSEtienne Carriere /* Load pin mux Alternate Function configuration, 4bit value */
6444b5e93edSEtienne Carriere if (pin < GPIO_ALT_LOWER_LIMIT) {
645077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRL_OFFSET,
646bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, pin << 2),
647bed4582fSEtienne Carriere SHIFT_U32(cfg->af, pin << 2));
6484b5e93edSEtienne Carriere } else {
6494b5e93edSEtienne Carriere size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
6504b5e93edSEtienne Carriere
651077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_AFRH_OFFSET,
652bed4582fSEtienne Carriere SHIFT_U32(GPIO_ALTERNATE_MASK, shift),
653bed4582fSEtienne Carriere SHIFT_U32(cfg->af, shift));
6544b5e93edSEtienne Carriere }
6554b5e93edSEtienne Carriere
6564b5e93edSEtienne Carriere /* Load GPIO Output direction confuguration, 1bit */
657077d486eSEtienne Carriere io_clrsetbits32(bank->base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin);
6584b5e93edSEtienne Carriere
659c4cab2bbSEtienne Carriere cpu_spin_unlock_xrestore(&gpio_lock, exceptions);
66098dfcedaSEtienne Carriere clk_disable(bank->clock);
6614b5e93edSEtienne Carriere }
6624b5e93edSEtienne Carriere
6634b5e93edSEtienne Carriere /* Count pins described in the DT node and get related data if possible */
get_pinctrl_from_fdt(const void * fdt,int node,int consumer_node __maybe_unused,struct stm32_pinctrl * pinctrl,size_t count)664b38386fbSEtienne Carriere static int get_pinctrl_from_fdt(const void *fdt, int node,
6655f27da69SEtienne Carriere int consumer_node __maybe_unused,
6664b5e93edSEtienne Carriere struct stm32_pinctrl *pinctrl, size_t count)
6674b5e93edSEtienne Carriere {
6685f27da69SEtienne Carriere struct stm32_gpio_bank *bank_ref = NULL;
669b38386fbSEtienne Carriere const fdt32_t *cuint = NULL;
670b38386fbSEtienne Carriere const fdt32_t *slewrate = NULL;
67110bcbd6cSEtienne Carriere int len = 0;
67210bcbd6cSEtienne Carriere uint32_t i = 0;
6734b5e93edSEtienne Carriere uint32_t speed = GPIO_OSPEED_LOW;
6744b5e93edSEtienne Carriere uint32_t pull = GPIO_PUPD_NO_PULL;
6754b5e93edSEtienne Carriere size_t found = 0;
6765f27da69SEtienne Carriere bool do_panic = false;
6774b5e93edSEtienne Carriere
6784b5e93edSEtienne Carriere cuint = fdt_getprop(fdt, node, "pinmux", &len);
6794b5e93edSEtienne Carriere if (!cuint)
6804b5e93edSEtienne Carriere return -FDT_ERR_NOTFOUND;
6814b5e93edSEtienne Carriere
6824b5e93edSEtienne Carriere slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
6834b5e93edSEtienne Carriere if (slewrate)
6844b5e93edSEtienne Carriere speed = fdt32_to_cpu(*slewrate);
6854b5e93edSEtienne Carriere
6864b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-up", NULL))
6874b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_UP;
6884b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "bias-pull-down", NULL))
6894b5e93edSEtienne Carriere pull = GPIO_PUPD_PULL_DOWN;
6904b5e93edSEtienne Carriere
6914b5e93edSEtienne Carriere for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
69210bcbd6cSEtienne Carriere uint32_t pincfg = 0;
69310bcbd6cSEtienne Carriere uint32_t bank = 0;
69410bcbd6cSEtienne Carriere uint32_t pin = 0;
69510bcbd6cSEtienne Carriere uint32_t mode = 0;
6964b5e93edSEtienne Carriere uint32_t alternate = 0;
697322cf9e3SEtienne Carriere uint32_t odata = 0;
6984b5e93edSEtienne Carriere bool opendrain = false;
6995f27da69SEtienne Carriere bool pin_non_secure = true;
7004b5e93edSEtienne Carriere
7014b5e93edSEtienne Carriere pincfg = fdt32_to_cpu(*cuint);
7024b5e93edSEtienne Carriere cuint++;
7034b5e93edSEtienne Carriere
7044b5e93edSEtienne Carriere bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
7054b5e93edSEtienne Carriere
7064b5e93edSEtienne Carriere pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
7074b5e93edSEtienne Carriere
7084b5e93edSEtienne Carriere mode = pincfg & DT_GPIO_MODE_MASK;
7094b5e93edSEtienne Carriere
7105f27da69SEtienne Carriere pin_non_secure = pincfg & STM32_PIN_NSEC;
7115f27da69SEtienne Carriere
7124b5e93edSEtienne Carriere switch (mode) {
7134b5e93edSEtienne Carriere case 0:
7144b5e93edSEtienne Carriere mode = GPIO_MODE_INPUT;
7154b5e93edSEtienne Carriere break;
7164b5e93edSEtienne Carriere case 1:
7174b5e93edSEtienne Carriere case 2:
7184b5e93edSEtienne Carriere case 3:
7194b5e93edSEtienne Carriere case 4:
7204b5e93edSEtienne Carriere case 5:
7214b5e93edSEtienne Carriere case 6:
7224b5e93edSEtienne Carriere case 7:
7234b5e93edSEtienne Carriere case 8:
7244b5e93edSEtienne Carriere case 9:
7254b5e93edSEtienne Carriere case 10:
7264b5e93edSEtienne Carriere case 11:
7274b5e93edSEtienne Carriere case 12:
7284b5e93edSEtienne Carriere case 13:
7294b5e93edSEtienne Carriere case 14:
7304b5e93edSEtienne Carriere case 15:
7314b5e93edSEtienne Carriere case 16:
7324b5e93edSEtienne Carriere alternate = mode - 1U;
7334b5e93edSEtienne Carriere mode = GPIO_MODE_ALTERNATE;
7344b5e93edSEtienne Carriere break;
7354b5e93edSEtienne Carriere case 17:
7364b5e93edSEtienne Carriere mode = GPIO_MODE_ANALOG;
7374b5e93edSEtienne Carriere break;
7384b5e93edSEtienne Carriere default:
7394b5e93edSEtienne Carriere mode = GPIO_MODE_OUTPUT;
7404b5e93edSEtienne Carriere break;
7414b5e93edSEtienne Carriere }
7424b5e93edSEtienne Carriere
7434b5e93edSEtienne Carriere if (fdt_getprop(fdt, node, "drive-open-drain", NULL))
7444b5e93edSEtienne Carriere opendrain = true;
7454b5e93edSEtienne Carriere
746322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-high", NULL) &&
747322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) {
748322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT;
749322cf9e3SEtienne Carriere odata = 1;
750322cf9e3SEtienne Carriere }
751322cf9e3SEtienne Carriere
752322cf9e3SEtienne Carriere if (fdt_getprop(fdt, node, "output-low", NULL) &&
753322cf9e3SEtienne Carriere mode == GPIO_MODE_INPUT) {
754322cf9e3SEtienne Carriere mode = GPIO_MODE_OUTPUT;
755322cf9e3SEtienne Carriere odata = 0;
756322cf9e3SEtienne Carriere }
757322cf9e3SEtienne Carriere
7584b5e93edSEtienne Carriere if (found < count) {
7594b5e93edSEtienne Carriere struct stm32_pinctrl *ref = &pinctrl[found];
7604b5e93edSEtienne Carriere
7614b5e93edSEtienne Carriere ref->bank = (uint8_t)bank;
7624b5e93edSEtienne Carriere ref->pin = (uint8_t)pin;
763b38386fbSEtienne Carriere ref->cfg.mode = mode;
764b38386fbSEtienne Carriere if (opendrain)
765b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_OPEN_DRAIN;
766b38386fbSEtienne Carriere else
767b38386fbSEtienne Carriere ref->cfg.otype = GPIO_OTYPE_PUSH_PULL;
768b38386fbSEtienne Carriere ref->cfg.ospeed = speed;
769b38386fbSEtienne Carriere ref->cfg.pupd = pull;
770b38386fbSEtienne Carriere ref->cfg.od = odata;
771b38386fbSEtienne Carriere ref->cfg.af = alternate;
7725f27da69SEtienne Carriere ref->cfg.nsec = pin_non_secure;
7735f27da69SEtienne Carriere
7745f27da69SEtienne Carriere bank_ref = stm32_gpio_get_bank(bank);
7755f27da69SEtienne Carriere
7765f27da69SEtienne Carriere if (pin >= bank_ref->ngpios) {
7775f27da69SEtienne Carriere EMSG("node %s requests pin %c%u that does not exist",
7785f27da69SEtienne Carriere fdt_get_name(fdt, consumer_node, NULL),
7795f27da69SEtienne Carriere bank + 'A', pin);
7805f27da69SEtienne Carriere do_panic = true;
7815f27da69SEtienne Carriere }
7824b5e93edSEtienne Carriere }
7834b5e93edSEtienne Carriere
7844b5e93edSEtienne Carriere found++;
7854b5e93edSEtienne Carriere }
7864b5e93edSEtienne Carriere
7875f27da69SEtienne Carriere if (do_panic)
7885f27da69SEtienne Carriere panic();
7895f27da69SEtienne Carriere
7904b5e93edSEtienne Carriere return (int)found;
7914b5e93edSEtienne Carriere }
7924b5e93edSEtienne Carriere
consumed_gpios_pm(enum pm_op op,unsigned int pm_hint __unused,const struct pm_callback_handle * pm_hdl)793bfc43b68SGatien Chevallier static TEE_Result consumed_gpios_pm(enum pm_op op,
794bfc43b68SGatien Chevallier unsigned int pm_hint __unused,
795bfc43b68SGatien Chevallier const struct pm_callback_handle *pm_hdl)
796bfc43b68SGatien Chevallier {
797bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *handle = pm_hdl->handle;
798bfc43b68SGatien Chevallier unsigned int bank_id = handle->gpio_pinctrl.bank;
799bfc43b68SGatien Chevallier unsigned int pin = handle->gpio_pinctrl.pin;
800bfc43b68SGatien Chevallier struct gpio_chip *chip = &stm32_gpio_get_bank(bank_id)->gpio_chip;
801bfc43b68SGatien Chevallier
802bfc43b68SGatien Chevallier if (op == PM_OP_RESUME) {
803bfc43b68SGatien Chevallier set_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
804bfc43b68SGatien Chevallier if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
805bfc43b68SGatien Chevallier stm32_gpio_set_level(chip, pin, handle->level);
806bfc43b68SGatien Chevallier } else {
807bfc43b68SGatien Chevallier get_gpio_cfg(bank_id, pin, &handle->gpio_pinctrl.cfg);
808bfc43b68SGatien Chevallier if (handle->gpio_pinctrl.cfg.mode == GPIO_MODE_OUTPUT)
809bfc43b68SGatien Chevallier handle->level = stm32_gpio_get_level(chip, pin);
810bfc43b68SGatien Chevallier }
811bfc43b68SGatien Chevallier
812bfc43b68SGatien Chevallier return TEE_SUCCESS;
813bfc43b68SGatien Chevallier }
814bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(consumed_gpios_pm);
815bfc43b68SGatien Chevallier
stm32_gpio_get_dt(struct dt_pargs * pargs,void * data,struct gpio ** out_gpio)816b357d34fSEtienne Carriere static TEE_Result stm32_gpio_get_dt(struct dt_pargs *pargs, void *data,
817b357d34fSEtienne Carriere struct gpio **out_gpio)
818420a32c5SEtienne Carriere {
819b357d34fSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC;
820430c415aSEtienne Carriere const char *consumer_name __maybe_unused = NULL;
8217761b658SEtienne Carriere struct stm32_gpio_pm_state *reg_state = NULL;
822bfc43b68SGatien Chevallier struct stm32_gpio_pm_state *state = NULL;
823420a32c5SEtienne Carriere struct stm32_gpio_bank *bank = data;
824420a32c5SEtienne Carriere struct gpio *gpio = NULL;
8254675225eSEtienne Carriere bool gpio_secure = true;
826420a32c5SEtienne Carriere
827430c415aSEtienne Carriere consumer_name = fdt_get_name(pargs->fdt, pargs->consumer_node,
828430c415aSEtienne Carriere NULL);
829430c415aSEtienne Carriere
830b357d34fSEtienne Carriere res = gpio_dt_alloc_pin(pargs, &gpio);
831b357d34fSEtienne Carriere if (res)
832b357d34fSEtienne Carriere return res;
833420a32c5SEtienne Carriere
834420a32c5SEtienne Carriere if (gpio->pin >= bank->ngpios) {
835420a32c5SEtienne Carriere DMSG("Invalid GPIO reference");
836420a32c5SEtienne Carriere free(gpio);
837b357d34fSEtienne Carriere return TEE_ERROR_GENERIC;
838420a32c5SEtienne Carriere }
839420a32c5SEtienne Carriere
8404675225eSEtienne Carriere if (gpio->dt_flags & GPIO_STM32_NSEC)
8414675225eSEtienne Carriere gpio_secure = false;
8424675225eSEtienne Carriere
843bfc43b68SGatien Chevallier state = calloc(1, sizeof(*state));
844bfc43b68SGatien Chevallier if (!state) {
845bfc43b68SGatien Chevallier free(gpio);
846bfc43b68SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY;
847bfc43b68SGatien Chevallier }
848bfc43b68SGatien Chevallier
8497761b658SEtienne Carriere SLIST_FOREACH(reg_state, &consumed_gpios_head, link) {
8507761b658SEtienne Carriere if (reg_state->gpio_pinctrl.bank == bank->bank_id &&
8517761b658SEtienne Carriere reg_state->gpio_pinctrl.pin == gpio->pin) {
8527761b658SEtienne Carriere EMSG("node %s: GPIO %c%u is used by another device",
8534675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin);
8547761b658SEtienne Carriere free(state);
8557761b658SEtienne Carriere free(gpio);
8567761b658SEtienne Carriere return TEE_ERROR_GENERIC;
8577761b658SEtienne Carriere }
8587761b658SEtienne Carriere }
8597761b658SEtienne Carriere
8604675225eSEtienne Carriere if (!pin_is_accessible(bank, gpio->pin)) {
8614675225eSEtienne Carriere EMSG("node %s requests pin on GPIO %c%u which access is denied",
8624675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin);
8634675225eSEtienne Carriere panic();
8644675225eSEtienne Carriere }
8654675225eSEtienne Carriere
866430c415aSEtienne Carriere res = acquire_rif_semaphore_if_needed(bank, gpio->pin);
867430c415aSEtienne Carriere if (res) {
868430c415aSEtienne Carriere EMSG("Failed to acquire GPIO %c%u semaphore for node %s",
869430c415aSEtienne Carriere bank->bank_id + 'A', gpio->pin, consumer_name);
870430c415aSEtienne Carriere return res;
871430c415aSEtienne Carriere }
872430c415aSEtienne Carriere
8734675225eSEtienne Carriere if (gpio_secure && !(bank->rif_cfg || bank->sec_support)) {
8744675225eSEtienne Carriere EMSG("node %s requests secure GPIO %c%u that cannot be secured",
8754675225eSEtienne Carriere consumer_name, bank->bank_id + 'A', gpio->pin);
8764675225eSEtienne Carriere panic();
8774675225eSEtienne Carriere }
8784675225eSEtienne Carriere
8794675225eSEtienne Carriere if (gpio_secure != pin_is_secure(bank, gpio->pin)) {
8804675225eSEtienne Carriere IMSG("WARNING: node %s requests %s GPIO %c%u but pin is %s. Check st,protreg in GPIO bank node %s",
8814675225eSEtienne Carriere consumer_name, gpio_secure ? "secure" : "non-secure",
8824675225eSEtienne Carriere bank->bank_id + 'A', gpio->pin,
8834675225eSEtienne Carriere pin_is_secure(bank, gpio->pin) ? "secure" : "non-secure",
8844675225eSEtienne Carriere fdt_get_name(pargs->fdt, pargs->phandle_node, NULL));
8854675225eSEtienne Carriere if (!IS_ENABLED(CFG_INSECURE))
8864675225eSEtienne Carriere panic();
8874675225eSEtienne Carriere }
8884675225eSEtienne Carriere
889bfc43b68SGatien Chevallier state->gpio_pinctrl.pin = gpio->pin;
890bfc43b68SGatien Chevallier state->gpio_pinctrl.bank = bank->bank_id;
891bfc43b68SGatien Chevallier SLIST_INSERT_HEAD(&consumed_gpios_head, state, link);
892bfc43b68SGatien Chevallier
893bfc43b68SGatien Chevallier register_pm_driver_cb(consumed_gpios_pm, state, "stm32-gpio-state");
894bfc43b68SGatien Chevallier
895420a32c5SEtienne Carriere gpio->chip = &bank->gpio_chip;
896420a32c5SEtienne Carriere
897b357d34fSEtienne Carriere *out_gpio = gpio;
898420a32c5SEtienne Carriere
899b357d34fSEtienne Carriere return TEE_SUCCESS;
900420a32c5SEtienne Carriere }
901420a32c5SEtienne Carriere
9029818a481SEtienne Carriere /* Get bank ID from bank node property st,bank-name or panic on failure */
dt_get_bank_id(const void * fdt,int node)9039818a481SEtienne Carriere static unsigned int dt_get_bank_id(const void *fdt, int node)
9049818a481SEtienne Carriere {
9059818a481SEtienne Carriere const int dt_name_len = strlen(DT_GPIO_BANK_NAME0);
9069818a481SEtienne Carriere const fdt32_t *cuint = NULL;
9079818a481SEtienne Carriere int len = 0;
9089818a481SEtienne Carriere
9099818a481SEtienne Carriere /* Parse "st,bank-name" to get its id (eg: GPIOA -> 0) */
9109818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "st,bank-name", &len);
9119818a481SEtienne Carriere if (!cuint || (len != dt_name_len + 1))
9129818a481SEtienne Carriere panic("Missing/wrong st,bank-name property");
9139818a481SEtienne Carriere
9149818a481SEtienne Carriere if (strncmp((const char *)cuint, DT_GPIO_BANK_NAME0, dt_name_len - 1) ||
9159818a481SEtienne Carriere strcmp((const char *)cuint, DT_GPIO_BANK_NAME0) < 0)
9169818a481SEtienne Carriere panic("Wrong st,bank-name property");
9179818a481SEtienne Carriere
9189818a481SEtienne Carriere return (unsigned int)strcmp((const char *)cuint, DT_GPIO_BANK_NAME0);
9199818a481SEtienne Carriere }
9209818a481SEtienne Carriere
9219818a481SEtienne Carriere /*
9229818a481SEtienne Carriere * Return whether or not the GPIO bank related to a DT node is already
9239818a481SEtienne Carriere * registered in the GPIO bank link.
9249818a481SEtienne Carriere */
bank_is_registered(const void * fdt,int node)9259818a481SEtienne Carriere static bool bank_is_registered(const void *fdt, int node)
9269818a481SEtienne Carriere {
9279818a481SEtienne Carriere unsigned int bank_id = dt_get_bank_id(fdt, node);
9289818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL;
9299818a481SEtienne Carriere
9309818a481SEtienne Carriere STAILQ_FOREACH(bank, &bank_list, link)
9319818a481SEtienne Carriere if (bank->bank_id == bank_id)
9329818a481SEtienne Carriere return true;
9339818a481SEtienne Carriere
9349818a481SEtienne Carriere return false;
9359818a481SEtienne Carriere }
9369818a481SEtienne Carriere
9379def1fb7SGatien Chevallier #ifdef CFG_STM32_RIF
handle_available_semaphores(struct stm32_gpio_bank * bank,uint32_t gpios_mask)938a72f07daSEtienne Carriere static TEE_Result handle_available_semaphores(struct stm32_gpio_bank *bank,
939a72f07daSEtienne Carriere uint32_t gpios_mask)
940bd03c8c3SGatien Chevallier {
941bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
942bd03c8c3SGatien Chevallier uint32_t cidcfgr = 0;
943bd03c8c3SGatien Chevallier unsigned int i = 0;
944bd03c8c3SGatien Chevallier
9459def1fb7SGatien Chevallier for (i = 0 ; i < bank->ngpios; i++) {
946a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask))
9479def1fb7SGatien Chevallier continue;
9489def1fb7SGatien Chevallier
9499def1fb7SGatien Chevallier cidcfgr = io_read32(bank->base + GPIO_CIDCFGR(i));
9509def1fb7SGatien Chevallier
9519def1fb7SGatien Chevallier if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
9529def1fb7SGatien Chevallier continue;
9539def1fb7SGatien Chevallier
9549def1fb7SGatien Chevallier if (!(io_read32(bank->base + GPIO_SECR_OFFSET) & BIT(i))) {
9559def1fb7SGatien Chevallier res = stm32_rif_release_semaphore(bank->base +
9569def1fb7SGatien Chevallier GPIO_SEMCR(i),
9579def1fb7SGatien Chevallier MAX_CID_SUPPORTED);
9589def1fb7SGatien Chevallier if (res) {
9599def1fb7SGatien Chevallier EMSG("Cannot release semaphore for resource %u",
9609def1fb7SGatien Chevallier i);
9619def1fb7SGatien Chevallier return res;
9629def1fb7SGatien Chevallier }
9639def1fb7SGatien Chevallier } else {
9649def1fb7SGatien Chevallier res = stm32_rif_acquire_semaphore(bank->base +
9659def1fb7SGatien Chevallier GPIO_SEMCR(i),
9669def1fb7SGatien Chevallier MAX_CID_SUPPORTED);
9679def1fb7SGatien Chevallier if (res) {
9689def1fb7SGatien Chevallier EMSG("Cannot acquire semaphore for resource %u",
9699def1fb7SGatien Chevallier i);
9709def1fb7SGatien Chevallier return res;
9719def1fb7SGatien Chevallier }
9729def1fb7SGatien Chevallier }
9739def1fb7SGatien Chevallier }
9749def1fb7SGatien Chevallier
9759def1fb7SGatien Chevallier return TEE_SUCCESS;
9769def1fb7SGatien Chevallier }
9779def1fb7SGatien Chevallier
apply_rif_config(struct stm32_gpio_bank * bank,uint32_t gpios_mask)978a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank,
979a72f07daSEtienne Carriere uint32_t gpios_mask)
9809def1fb7SGatien Chevallier {
9819def1fb7SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
9829def1fb7SGatien Chevallier unsigned int i = 0;
9839def1fb7SGatien Chevallier
984bd03c8c3SGatien Chevallier if (!bank->rif_cfg)
985bd03c8c3SGatien Chevallier return TEE_SUCCESS;
986bd03c8c3SGatien Chevallier
987bd03c8c3SGatien Chevallier if (clk_enable(bank->clock))
988bd03c8c3SGatien Chevallier panic();
989bd03c8c3SGatien Chevallier
9909def1fb7SGatien Chevallier if (bank->is_tdcid) {
991bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) {
992a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask))
993bd03c8c3SGatien Chevallier continue;
994bd03c8c3SGatien Chevallier
995bd03c8c3SGatien Chevallier /*
9969def1fb7SGatien Chevallier * When TDCID, OP-TEE should be the one to set the CID
9979def1fb7SGatien Chevallier * filtering configuration. Clearing previous
9989def1fb7SGatien Chevallier * configuration prevents undesired events during the
9999def1fb7SGatien Chevallier * only legitimate configuration.
1000bd03c8c3SGatien Chevallier */
1001bd03c8c3SGatien Chevallier io_clrbits32(bank->base + GPIO_CIDCFGR(i),
1002bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK);
1003bd03c8c3SGatien Chevallier }
10049def1fb7SGatien Chevallier } else {
1005a72f07daSEtienne Carriere res = handle_available_semaphores(bank, gpios_mask);
10069def1fb7SGatien Chevallier if (res)
10079def1fb7SGatien Chevallier panic();
1008bd03c8c3SGatien Chevallier }
1009bd03c8c3SGatien Chevallier
1010bd03c8c3SGatien Chevallier /* Security and privilege RIF configuration */
1011a72f07daSEtienne Carriere io_mask32(bank->base + GPIO_PRIVCFGR_OFFSET,
1012a72f07daSEtienne Carriere bank->rif_cfg->priv_conf[0], gpios_mask);
1013a72f07daSEtienne Carriere io_mask32(bank->base + GPIO_SECR_OFFSET,
1014a72f07daSEtienne Carriere bank->rif_cfg->sec_conf[0], gpios_mask);
1015bd03c8c3SGatien Chevallier
1016bd03c8c3SGatien Chevallier if (!bank->is_tdcid) {
1017bd03c8c3SGatien Chevallier res = TEE_SUCCESS;
1018bd03c8c3SGatien Chevallier goto out;
1019bd03c8c3SGatien Chevallier }
1020bd03c8c3SGatien Chevallier
1021bd03c8c3SGatien Chevallier for (i = 0; i < bank->ngpios; i++) {
1022a72f07daSEtienne Carriere if (!(BIT(i) & gpios_mask))
1023bd03c8c3SGatien Chevallier continue;
1024bd03c8c3SGatien Chevallier
1025bd03c8c3SGatien Chevallier io_clrsetbits32(bank->base + GPIO_CIDCFGR(i),
1026bd03c8c3SGatien Chevallier GPIO_CIDCFGR_CONF_MASK,
1027bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs[i]);
1028bd03c8c3SGatien Chevallier }
1029bd03c8c3SGatien Chevallier
1030bd03c8c3SGatien Chevallier /*
1031bd03c8c3SGatien Chevallier * Lock RIF configuration if configured. This cannot be undone until
1032bd03c8c3SGatien Chevallier * next reset.
1033bd03c8c3SGatien Chevallier */
1034bd03c8c3SGatien Chevallier io_setbits32(bank->base + GPIO_RCFGLOCKR_OFFSET,
1035bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf[0]);
1036bd03c8c3SGatien Chevallier
1037a72f07daSEtienne Carriere res = handle_available_semaphores(bank, gpios_mask);
10389def1fb7SGatien Chevallier if (res)
10399def1fb7SGatien Chevallier panic();
10409def1fb7SGatien Chevallier
10419def1fb7SGatien Chevallier out:
1042bd03c8c3SGatien Chevallier if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) {
1043bd03c8c3SGatien Chevallier /* Check that RIF config are applied, panic otherwise */
1044bd03c8c3SGatien Chevallier if ((io_read32(bank->base + GPIO_PRIVCFGR_OFFSET) &
1045a72f07daSEtienne Carriere gpios_mask) !=
1046a72f07daSEtienne Carriere (bank->rif_cfg->priv_conf[0] & gpios_mask)) {
1047bd03c8c3SGatien Chevallier EMSG("GPIO bank%c priv conf is incorrect",
1048bd03c8c3SGatien Chevallier 'A' + bank->bank_id);
1049bd03c8c3SGatien Chevallier panic();
1050bd03c8c3SGatien Chevallier }
1051bd03c8c3SGatien Chevallier
1052a72f07daSEtienne Carriere if ((io_read32(bank->base + GPIO_SECR_OFFSET) & gpios_mask) !=
1053a72f07daSEtienne Carriere (bank->rif_cfg->sec_conf[0] & gpios_mask)) {
1054bd03c8c3SGatien Chevallier EMSG("GPIO bank %c sec conf is incorrect",
1055bd03c8c3SGatien Chevallier 'A' + bank->bank_id);
1056bd03c8c3SGatien Chevallier panic();
1057bd03c8c3SGatien Chevallier }
1058bd03c8c3SGatien Chevallier }
1059bd03c8c3SGatien Chevallier
1060bd03c8c3SGatien Chevallier clk_disable(bank->clock);
1061bd03c8c3SGatien Chevallier
1062bd03c8c3SGatien Chevallier return res;
1063bd03c8c3SGatien Chevallier }
10649def1fb7SGatien Chevallier #else /* CFG_STM32_RIF */
apply_rif_config(struct stm32_gpio_bank * bank __unused,uint32_t gpios_mask __unused)1065a72f07daSEtienne Carriere static TEE_Result apply_rif_config(struct stm32_gpio_bank *bank __unused,
1066a72f07daSEtienne Carriere uint32_t gpios_mask __unused)
10679def1fb7SGatien Chevallier {
10689def1fb7SGatien Chevallier return TEE_SUCCESS;
10699def1fb7SGatien Chevallier }
10709def1fb7SGatien Chevallier #endif /* CFG_STM32_RIF */
1071bd03c8c3SGatien Chevallier
1072a650c9cbSEtienne Carriere /* Forward reference to stm32_gpio_set_conf_sec() defined below */
1073a650c9cbSEtienne Carriere static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank);
1074a650c9cbSEtienne Carriere
stm32_gpio_fw_configure(struct firewall_query * firewall)1075a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_fw_configure(struct firewall_query *firewall)
1076a650c9cbSEtienne Carriere {
1077a650c9cbSEtienne Carriere struct stm32_gpio_bank *bank = firewall->ctrl->priv;
1078a650c9cbSEtienne Carriere uint32_t firewall_arg = 0;
1079a650c9cbSEtienne Carriere uint32_t gpios_mask = 0;
1080a650c9cbSEtienne Carriere bool secure = true;
1081a650c9cbSEtienne Carriere
1082a650c9cbSEtienne Carriere assert(bank->sec_support);
1083a650c9cbSEtienne Carriere
1084a650c9cbSEtienne Carriere if (firewall->arg_count != 1)
1085a650c9cbSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS;
1086a650c9cbSEtienne Carriere
1087a650c9cbSEtienne Carriere firewall_arg = firewall->args[0];
1088a650c9cbSEtienne Carriere
1089a650c9cbSEtienne Carriere if (bank->rif_cfg) {
1090a650c9cbSEtienne Carriere gpios_mask = BIT(RIF_CHANNEL_ID(firewall_arg));
1091a650c9cbSEtienne Carriere
1092a650c9cbSEtienne Carriere /* We're about to change a specific GPIO config */
1093a650c9cbSEtienne Carriere bank->rif_cfg->access_mask[0] |= gpios_mask;
1094a650c9cbSEtienne Carriere
1095a650c9cbSEtienne Carriere /*
1096a650c9cbSEtienne Carriere * Update bank RIF config with firewall configuration data
1097a650c9cbSEtienne Carriere * and apply it.
1098a650c9cbSEtienne Carriere */
1099a650c9cbSEtienne Carriere stm32_rif_parse_cfg(firewall_arg, bank->rif_cfg,
1100a650c9cbSEtienne Carriere bank->ngpios);
1101a650c9cbSEtienne Carriere return apply_rif_config(bank, gpios_mask);
1102a650c9cbSEtienne Carriere }
1103a650c9cbSEtienne Carriere
1104a650c9cbSEtienne Carriere /*
1105a650c9cbSEtienne Carriere * Non RIF GPIO banks use a single cell as a bit mask (bits 0 to 15)
1106a650c9cbSEtienne Carriere * to define the a group of GPIO pins (one or several) to configure
1107a650c9cbSEtienne Carriere * for that bank, and GPIO_STM32_NSEC bit flag to set if these pins
1108a650c9cbSEtienne Carriere * are non-secure (flag set) or non-secure (flag cleared).
1109a650c9cbSEtienne Carriere */
1110a650c9cbSEtienne Carriere gpios_mask = firewall_arg & GENMASK_32(15, 0);
1111a650c9cbSEtienne Carriere
1112a650c9cbSEtienne Carriere secure = !(firewall_arg & GPIO_STM32_NSEC);
1113a650c9cbSEtienne Carriere
1114a650c9cbSEtienne Carriere if (gpios_mask & ~GENMASK_32(bank->ngpios, 0)) {
1115a650c9cbSEtienne Carriere EMSG("Invalid bitmask %#"PRIx32" for GPIO bank %c",
1116a650c9cbSEtienne Carriere gpios_mask, 'A' + bank->bank_id);
1117a650c9cbSEtienne Carriere return TEE_ERROR_GENERIC;
1118a650c9cbSEtienne Carriere }
1119a650c9cbSEtienne Carriere
1120a650c9cbSEtienne Carriere /* Update bank secure register configuration data and apply it */
1121a650c9cbSEtienne Carriere if (secure)
1122a650c9cbSEtienne Carriere bank->seccfgr |= gpios_mask;
1123a650c9cbSEtienne Carriere else
1124a650c9cbSEtienne Carriere bank->seccfgr &= ~gpios_mask;
1125a650c9cbSEtienne Carriere
1126a650c9cbSEtienne Carriere stm32_gpio_set_conf_sec(bank);
1127a650c9cbSEtienne Carriere
1128a650c9cbSEtienne Carriere return TEE_SUCCESS;
1129a650c9cbSEtienne Carriere }
1130a650c9cbSEtienne Carriere
1131a650c9cbSEtienne Carriere static const struct firewall_controller_ops stm32_gpio_firewall_ops = {
1132a650c9cbSEtienne Carriere .set_conf = stm32_gpio_fw_configure,
1133a650c9cbSEtienne Carriere };
1134a650c9cbSEtienne Carriere
stm32_gpio_save_rif_config(struct stm32_gpio_bank * bank)1135bfc43b68SGatien Chevallier static void stm32_gpio_save_rif_config(struct stm32_gpio_bank *bank)
1136bfc43b68SGatien Chevallier {
1137bfc43b68SGatien Chevallier size_t i = 0;
1138bfc43b68SGatien Chevallier
1139bfc43b68SGatien Chevallier for (i = 0; i < bank->ngpios; i++)
1140bfc43b68SGatien Chevallier bank->rif_cfg->cid_confs[i] = io_read32(bank->base +
1141bfc43b68SGatien Chevallier GPIO_CIDCFGR(i));
1142bfc43b68SGatien Chevallier
1143bfc43b68SGatien Chevallier bank->rif_cfg->priv_conf[0] = io_read32(bank->base +
1144bfc43b68SGatien Chevallier GPIO_PRIVCFGR_OFFSET);
1145bfc43b68SGatien Chevallier bank->rif_cfg->sec_conf[0] = io_read32(bank->base +
1146bfc43b68SGatien Chevallier GPIO_SECR_OFFSET);
1147bfc43b68SGatien Chevallier bank->rif_cfg->lock_conf[0] = io_read32(bank->base +
1148bfc43b68SGatien Chevallier GPIO_RCFGLOCKR_OFFSET);
1149bfc43b68SGatien Chevallier }
1150bfc43b68SGatien Chevallier
stm32_parse_gpio_rif_conf(struct stm32_gpio_bank * bank,const void * fdt,int node)1151bd03c8c3SGatien Chevallier static void stm32_parse_gpio_rif_conf(struct stm32_gpio_bank *bank,
1152bd03c8c3SGatien Chevallier const void *fdt, int node)
1153bd03c8c3SGatien Chevallier {
1154bd03c8c3SGatien Chevallier unsigned int i = 0;
1155bd03c8c3SGatien Chevallier unsigned int nb_rif_conf = 0;
1156bd03c8c3SGatien Chevallier int lenp = 0;
1157bd03c8c3SGatien Chevallier const fdt32_t *cuint = NULL;
1158bd03c8c3SGatien Chevallier
1159bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
1160bd03c8c3SGatien Chevallier if (!cuint) {
1161bd03c8c3SGatien Chevallier DMSG("No RIF configuration available");
1162bd03c8c3SGatien Chevallier return;
1163bd03c8c3SGatien Chevallier }
1164bd03c8c3SGatien Chevallier
1165bd03c8c3SGatien Chevallier bank->rif_cfg = calloc(1, sizeof(*bank->rif_cfg));
1166bd03c8c3SGatien Chevallier if (!bank->rif_cfg)
1167bd03c8c3SGatien Chevallier panic();
1168bd03c8c3SGatien Chevallier
1169bd03c8c3SGatien Chevallier bank->rif_cfg->sec_conf = calloc(1, sizeof(uint32_t));
1170bd03c8c3SGatien Chevallier if (!bank->rif_cfg->sec_conf)
1171bd03c8c3SGatien Chevallier panic();
1172bd03c8c3SGatien Chevallier
1173b290af13SThomas Bourgoin nb_rif_conf = MIN((unsigned int)(lenp / sizeof(uint32_t)),
1174b290af13SThomas Bourgoin bank->ngpios);
1175bd03c8c3SGatien Chevallier
1176bd03c8c3SGatien Chevallier bank->rif_cfg->cid_confs = calloc(bank->ngpios, sizeof(uint32_t));
1177bd03c8c3SGatien Chevallier bank->rif_cfg->priv_conf = calloc(1, sizeof(uint32_t));
1178bd03c8c3SGatien Chevallier bank->rif_cfg->lock_conf = calloc(1, sizeof(uint32_t));
1179bd03c8c3SGatien Chevallier bank->rif_cfg->access_mask = calloc(1, sizeof(uint32_t));
1180bd03c8c3SGatien Chevallier if (!bank->rif_cfg->cid_confs || !bank->rif_cfg->access_mask ||
1181bd03c8c3SGatien Chevallier !bank->rif_cfg->priv_conf || !bank->rif_cfg->lock_conf)
1182bd03c8c3SGatien Chevallier panic("Missing memory capacity for GPIOS RIF configuration");
1183bd03c8c3SGatien Chevallier
1184bd03c8c3SGatien Chevallier for (i = 0; i < nb_rif_conf; i++)
1185bd03c8c3SGatien Chevallier stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), bank->rif_cfg,
1186646ad62bSGatien Chevallier bank->ngpios);
1187bd03c8c3SGatien Chevallier }
1188bd03c8c3SGatien Chevallier
11899818a481SEtienne Carriere /* Get GPIO bank information from the DT */
dt_stm32_gpio_bank(const void * fdt,int node,const void * compat_data,int range_offset,struct stm32_gpio_bank ** out_bank)11909818a481SEtienne Carriere static TEE_Result dt_stm32_gpio_bank(const void *fdt, int node,
1191e569f6adSEtienne Carriere const void *compat_data,
11929818a481SEtienne Carriere int range_offset,
11939818a481SEtienne Carriere struct stm32_gpio_bank **out_bank)
11949818a481SEtienne Carriere {
1195e569f6adSEtienne Carriere const struct bank_compat *compat = compat_data;
11969818a481SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC;
11979818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL;
11989818a481SEtienne Carriere const fdt32_t *cuint = NULL;
11999818a481SEtienne Carriere struct io_pa_va pa_va = { };
12009818a481SEtienne Carriere struct clk *clk = NULL;
12019818a481SEtienne Carriere size_t blen = 0;
12029818a481SEtienne Carriere paddr_t pa = 0;
12039818a481SEtienne Carriere int len = 0;
12049818a481SEtienne Carriere int i = 0;
12059818a481SEtienne Carriere
12069818a481SEtienne Carriere assert(out_bank);
12079818a481SEtienne Carriere
12089818a481SEtienne Carriere /* Probe deferrable devices first */
12099818a481SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &clk);
12109818a481SEtienne Carriere if (res)
12119818a481SEtienne Carriere return res;
12129818a481SEtienne Carriere
12139818a481SEtienne Carriere bank = calloc(1, sizeof(*bank));
12149818a481SEtienne Carriere if (!bank)
12159818a481SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY;
12169818a481SEtienne Carriere
1217bd03c8c3SGatien Chevallier if (compat->secure_extended) {
1218bd03c8c3SGatien Chevallier res = stm32_rifsc_check_tdcid(&bank->is_tdcid);
1219bd03c8c3SGatien Chevallier if (res) {
1220bd03c8c3SGatien Chevallier free(bank);
1221bd03c8c3SGatien Chevallier return res;
1222bd03c8c3SGatien Chevallier }
1223bd03c8c3SGatien Chevallier }
1224bd03c8c3SGatien Chevallier
12259818a481SEtienne Carriere /*
12269818a481SEtienne Carriere * Do not rely *only* on the "reg" property to get the address,
12279818a481SEtienne Carriere * but consider also the "ranges" translation property
12289818a481SEtienne Carriere */
12296a0116edSEtienne Carriere if (fdt_reg_info(fdt, node, &pa, &blen))
12306a0116edSEtienne Carriere panic("missing reg or reg size property");
12319818a481SEtienne Carriere
12329818a481SEtienne Carriere pa_va.pa = pa + range_offset;
12339818a481SEtienne Carriere
12349818a481SEtienne Carriere DMSG("Bank name %s", fdt_get_name(fdt, node, NULL));
12359818a481SEtienne Carriere bank->bank_id = dt_get_bank_id(fdt, node);
12369818a481SEtienne Carriere bank->clock = clk;
1237420a32c5SEtienne Carriere bank->gpio_chip.ops = &stm32_gpio_ops;
1238b4893304SGatien Chevallier bank->sec_support = compat->secure_control;
12399818a481SEtienne Carriere
12409818a481SEtienne Carriere /* Parse gpio-ranges with its 4 parameters */
12419818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
12429818a481SEtienne Carriere len /= sizeof(*cuint);
12439818a481SEtienne Carriere if (len % 4)
12449818a481SEtienne Carriere panic("wrong gpio-ranges syntax");
12459818a481SEtienne Carriere
12469818a481SEtienne Carriere /* Get the last defined gpio line (offset + nb of pins) */
12479818a481SEtienne Carriere for (i = 0; i < len / 4; i++) {
12489818a481SEtienne Carriere bank->ngpios = MAX(bank->ngpios,
12499818a481SEtienne Carriere (unsigned int)(fdt32_to_cpu(*(cuint + 1)) +
12509818a481SEtienne Carriere fdt32_to_cpu(*(cuint + 3))));
12519818a481SEtienne Carriere cuint += 4;
12529818a481SEtienne Carriere }
12539818a481SEtienne Carriere
1254bd03c8c3SGatien Chevallier if (compat->secure_extended) {
1255bd03c8c3SGatien Chevallier /* RIF configuration */
1256bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen);
1257bd03c8c3SGatien Chevallier
1258bd03c8c3SGatien Chevallier stm32_parse_gpio_rif_conf(bank, fdt, node);
1259bd03c8c3SGatien Chevallier } else if (bank->sec_support) {
1260bd03c8c3SGatien Chevallier /* Secure configuration */
1261bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_secure(&pa_va, blen);
1262bd03c8c3SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", NULL);
1263bd03c8c3SGatien Chevallier if (cuint)
1264bd03c8c3SGatien Chevallier bank->seccfgr = fdt32_to_cpu(*cuint);
1265bd03c8c3SGatien Chevallier else
1266bd03c8c3SGatien Chevallier DMSG("GPIO bank %c assigned to non-secure",
1267bd03c8c3SGatien Chevallier bank->bank_id + 'A');
1268bd03c8c3SGatien Chevallier } else {
1269bd03c8c3SGatien Chevallier bank->base = io_pa_or_va_nsec(&pa_va, blen);
1270bd03c8c3SGatien Chevallier }
1271bd03c8c3SGatien Chevallier
12729818a481SEtienne Carriere *out_bank = bank;
1273bd03c8c3SGatien Chevallier
12749818a481SEtienne Carriere return TEE_SUCCESS;
12759818a481SEtienne Carriere }
12769818a481SEtienne Carriere
stm32_gpio_firewall_register(const void * fdt,int node,struct stm32_gpio_bank * bank)1277a650c9cbSEtienne Carriere static TEE_Result stm32_gpio_firewall_register(const void *fdt, int node,
1278a650c9cbSEtienne Carriere struct stm32_gpio_bank *bank)
1279a650c9cbSEtienne Carriere {
1280a650c9cbSEtienne Carriere struct firewall_controller *controller = NULL;
1281a650c9cbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC;
1282a650c9cbSEtienne Carriere char bank_name[] = "gpio-bank-X";
1283a650c9cbSEtienne Carriere char *name = NULL;
1284a650c9cbSEtienne Carriere
1285a650c9cbSEtienne Carriere if (!IS_ENABLED(CFG_DRIVERS_FIREWALL) ||
1286a650c9cbSEtienne Carriere !bank->sec_support)
1287a650c9cbSEtienne Carriere return TEE_SUCCESS;
1288a650c9cbSEtienne Carriere
1289a650c9cbSEtienne Carriere controller = calloc(1, sizeof(*controller));
1290a650c9cbSEtienne Carriere if (!controller)
1291a650c9cbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY;
1292a650c9cbSEtienne Carriere
1293a650c9cbSEtienne Carriere bank_name[sizeof(bank_name) - 2] = 'A' + bank->bank_id;
1294a650c9cbSEtienne Carriere name = strdup(bank_name);
1295a650c9cbSEtienne Carriere
1296a650c9cbSEtienne Carriere controller->name = name;
1297a650c9cbSEtienne Carriere controller->priv = bank;
1298a650c9cbSEtienne Carriere controller->ops = &stm32_gpio_firewall_ops;
1299a650c9cbSEtienne Carriere
1300a650c9cbSEtienne Carriere if (!controller->name)
1301a650c9cbSEtienne Carriere EMSG("Warning: out of memory to store bank name");
1302a650c9cbSEtienne Carriere
1303a650c9cbSEtienne Carriere res = firewall_dt_controller_register(fdt, node, controller);
1304a650c9cbSEtienne Carriere if (res) {
1305a650c9cbSEtienne Carriere free(name);
1306a650c9cbSEtienne Carriere free(controller);
1307a650c9cbSEtienne Carriere }
1308a650c9cbSEtienne Carriere
1309a650c9cbSEtienne Carriere return res;
1310a650c9cbSEtienne Carriere }
1311a650c9cbSEtienne Carriere
1312bd03c8c3SGatien Chevallier /* Parse a pinctrl node to register the GPIO banks it describes */
dt_stm32_gpio_pinctrl(const void * fdt,int node,const void * compat_data)13130e0435e2SEtienne Carriere static TEE_Result dt_stm32_gpio_pinctrl(const void *fdt, int node,
13149818a481SEtienne Carriere const void *compat_data)
13159818a481SEtienne Carriere {
13169818a481SEtienne Carriere TEE_Result res = TEE_SUCCESS;
13179818a481SEtienne Carriere const fdt32_t *cuint = NULL;
13189818a481SEtienne Carriere int range_offs = 0;
13199818a481SEtienne Carriere int b_node = 0;
13209818a481SEtienne Carriere int len = 0;
13219818a481SEtienne Carriere
13229818a481SEtienne Carriere /* Read the ranges property (for regs memory translation) */
13239818a481SEtienne Carriere cuint = fdt_getprop(fdt, node, "ranges", &len);
13249818a481SEtienne Carriere if (!cuint)
13259818a481SEtienne Carriere panic("missing ranges property");
13269818a481SEtienne Carriere
13279818a481SEtienne Carriere len /= sizeof(*cuint);
13289818a481SEtienne Carriere if (len == 3)
13299818a481SEtienne Carriere range_offs = fdt32_to_cpu(*(cuint + 1)) - fdt32_to_cpu(*cuint);
13309818a481SEtienne Carriere
13319818a481SEtienne Carriere fdt_for_each_subnode(b_node, fdt, node) {
13329818a481SEtienne Carriere cuint = fdt_getprop(fdt, b_node, "gpio-controller", &len);
13339818a481SEtienne Carriere if (cuint) {
13349818a481SEtienne Carriere /*
13359818a481SEtienne Carriere * We found a property "gpio-controller" in the node:
13369818a481SEtienne Carriere * the node is a GPIO bank description, add it to the
13379818a481SEtienne Carriere * bank list.
13389818a481SEtienne Carriere */
13399818a481SEtienne Carriere struct stm32_gpio_bank *bank = NULL;
13409818a481SEtienne Carriere
13419818a481SEtienne Carriere if (fdt_get_status(fdt, b_node) == DT_STATUS_DISABLED ||
13429818a481SEtienne Carriere bank_is_registered(fdt, b_node))
13439818a481SEtienne Carriere continue;
13449818a481SEtienne Carriere
13459818a481SEtienne Carriere res = dt_stm32_gpio_bank(fdt, b_node, compat_data,
13469818a481SEtienne Carriere range_offs, &bank);
13479818a481SEtienne Carriere if (res)
13489818a481SEtienne Carriere return res;
13499818a481SEtienne Carriere
1350420a32c5SEtienne Carriere /* Registering a provider should not defer probe */
1351420a32c5SEtienne Carriere res = gpio_register_provider(fdt, b_node,
1352420a32c5SEtienne Carriere stm32_gpio_get_dt, bank);
1353420a32c5SEtienne Carriere if (res)
1354420a32c5SEtienne Carriere panic();
1355420a32c5SEtienne Carriere
1356a650c9cbSEtienne Carriere res = stm32_gpio_firewall_register(fdt, b_node, bank);
1357a650c9cbSEtienne Carriere if (res)
1358a650c9cbSEtienne Carriere panic();
1359a650c9cbSEtienne Carriere
13609818a481SEtienne Carriere STAILQ_INSERT_TAIL(&bank_list, bank, link);
13619818a481SEtienne Carriere } else {
13629818a481SEtienne Carriere if (len != -FDT_ERR_NOTFOUND)
13639818a481SEtienne Carriere panic();
13649818a481SEtienne Carriere }
13659818a481SEtienne Carriere }
13669818a481SEtienne Carriere
13679818a481SEtienne Carriere return TEE_SUCCESS;
13689818a481SEtienne Carriere }
13699818a481SEtienne Carriere
1370b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
stm32_pinctrl_conf_apply(struct pinconf * conf)1371b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_conf_apply(struct pinconf *conf)
1372b38386fbSEtienne Carriere {
1373b38386fbSEtienne Carriere struct stm32_pinctrl_array *ref = conf->priv;
1374b38386fbSEtienne Carriere struct stm32_pinctrl *p = ref->pinctrl;
1375430c415aSEtienne Carriere struct stm32_gpio_bank *bank = NULL;
1376430c415aSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC;
1377b38386fbSEtienne Carriere size_t pin_count = ref->count;
1378b38386fbSEtienne Carriere size_t n = 0;
1379430c415aSEtienne Carriere bool error = false;
1380430c415aSEtienne Carriere
1381430c415aSEtienne Carriere for (n = 0; n < pin_count; n++) {
1382430c415aSEtienne Carriere bank = stm32_gpio_get_bank(p[n].bank);
13835f27da69SEtienne Carriere
13845f27da69SEtienne Carriere if (!pin_is_accessible(bank, p[n].pin)) {
13855f27da69SEtienne Carriere EMSG("Apply pinctrl for pin %c%u that cannot be accessed",
13865f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin);
13875f27da69SEtienne Carriere error = true;
13885f27da69SEtienne Carriere continue;
13895f27da69SEtienne Carriere }
13905f27da69SEtienne Carriere
1391430c415aSEtienne Carriere res = acquire_rif_semaphore_if_needed(bank, p[n].pin);
1392430c415aSEtienne Carriere if (res) {
1393430c415aSEtienne Carriere EMSG("Failed to acquire GPIO %c%u semaphore",
1394430c415aSEtienne Carriere bank->bank_id + 'A', p[n].pin);
1395430c415aSEtienne Carriere error = true;
13965f27da69SEtienne Carriere continue;
13975f27da69SEtienne Carriere }
13985f27da69SEtienne Carriere
13995f27da69SEtienne Carriere if (p[n].cfg.nsec == !pin_is_secure(bank, p[n].pin))
14005f27da69SEtienne Carriere continue;
14015f27da69SEtienne Carriere
14025f27da69SEtienne Carriere if (IS_ENABLED(CFG_INSECURE)) {
14035f27da69SEtienne Carriere IMSG("WARNING: apply pinctrl for %ssecure pin %c%u that is %ssecure",
14045f27da69SEtienne Carriere p[n].cfg.nsec ? "non-" : "",
14055f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin,
14065f27da69SEtienne Carriere pin_is_secure(bank, p[n].pin) ? "" : "non-");
14075f27da69SEtienne Carriere } else {
14085f27da69SEtienne Carriere EMSG("Apply pinctrl for %ssecure pin %c%u that is %ssecure",
14095f27da69SEtienne Carriere p[n].cfg.nsec ? "non-" : "",
14105f27da69SEtienne Carriere p[n].bank + 'A', p[n].pin,
14115f27da69SEtienne Carriere pin_is_secure(bank, p[n].pin) ? "" : "non-");
14125f27da69SEtienne Carriere error = true;
1413430c415aSEtienne Carriere }
1414430c415aSEtienne Carriere }
1415430c415aSEtienne Carriere
1416430c415aSEtienne Carriere if (error) {
1417430c415aSEtienne Carriere for (n = 0; n < pin_count; n++) {
1418430c415aSEtienne Carriere bank = stm32_gpio_get_bank(p[n].bank);
1419430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, p[n].pin);
1420430c415aSEtienne Carriere }
1421430c415aSEtienne Carriere
1422430c415aSEtienne Carriere return TEE_ERROR_SECURITY;
1423430c415aSEtienne Carriere }
1424b38386fbSEtienne Carriere
1425b38386fbSEtienne Carriere for (n = 0; n < pin_count; n++)
1426b38386fbSEtienne Carriere set_gpio_cfg(p[n].bank, p[n].pin, &p[n].cfg);
1427b38386fbSEtienne Carriere
1428b38386fbSEtienne Carriere return TEE_SUCCESS;
1429b38386fbSEtienne Carriere }
1430b38386fbSEtienne Carriere
stm32_pinctrl_conf_free(struct pinconf * conf)1431b38386fbSEtienne Carriere static void stm32_pinctrl_conf_free(struct pinconf *conf)
1432b38386fbSEtienne Carriere {
1433b38386fbSEtienne Carriere free(conf);
1434b38386fbSEtienne Carriere }
1435b38386fbSEtienne Carriere
1436b38386fbSEtienne Carriere static const struct pinctrl_ops stm32_pinctrl_ops = {
1437b38386fbSEtienne Carriere .conf_apply = stm32_pinctrl_conf_apply,
1438b38386fbSEtienne Carriere .conf_free = stm32_pinctrl_conf_free,
1439b38386fbSEtienne Carriere };
1440b38386fbSEtienne Carriere
1441b38386fbSEtienne Carriere DECLARE_KEEP_PAGER(stm32_pinctrl_ops);
1442b38386fbSEtienne Carriere
stm32_gpio_pinctrl_bank_pin(struct pinctrl_state * pinctrl,unsigned int * bank,unsigned int * pin,unsigned int * count)144370ac0db5SEtienne Carriere void stm32_gpio_pinctrl_bank_pin(struct pinctrl_state *pinctrl,
144470ac0db5SEtienne Carriere unsigned int *bank, unsigned int *pin,
144570ac0db5SEtienne Carriere unsigned int *count)
144670ac0db5SEtienne Carriere {
144770ac0db5SEtienne Carriere size_t conf_index = 0;
144870ac0db5SEtienne Carriere size_t pin_count = 0;
144970ac0db5SEtienne Carriere size_t n = 0;
145070ac0db5SEtienne Carriere
145170ac0db5SEtienne Carriere assert(count);
145270ac0db5SEtienne Carriere if (!pinctrl)
145370ac0db5SEtienne Carriere goto out;
145470ac0db5SEtienne Carriere
145570ac0db5SEtienne Carriere for (conf_index = 0; conf_index < pinctrl->conf_count; conf_index++) {
145670ac0db5SEtienne Carriere struct pinconf *pinconf = pinctrl->confs[conf_index];
145770ac0db5SEtienne Carriere struct stm32_pinctrl_array *ref = pinconf->priv;
145870ac0db5SEtienne Carriere
145970ac0db5SEtienne Carriere /* Consider only the stm32_gpio pins */
146070ac0db5SEtienne Carriere if (pinconf->ops != &stm32_pinctrl_ops)
146170ac0db5SEtienne Carriere continue;
146270ac0db5SEtienne Carriere
146370ac0db5SEtienne Carriere if (bank || pin) {
146470ac0db5SEtienne Carriere for (n = 0; n < ref->count; n++) {
146570ac0db5SEtienne Carriere if (bank && pin_count < *count)
146670ac0db5SEtienne Carriere bank[pin_count] = ref->pinctrl[n].bank;
146770ac0db5SEtienne Carriere if (pin && pin_count < *count)
146870ac0db5SEtienne Carriere pin[pin_count] = ref->pinctrl[n].pin;
146970ac0db5SEtienne Carriere pin_count++;
147070ac0db5SEtienne Carriere }
147170ac0db5SEtienne Carriere } else {
147270ac0db5SEtienne Carriere pin_count += ref->count;
147370ac0db5SEtienne Carriere }
147470ac0db5SEtienne Carriere }
147570ac0db5SEtienne Carriere
147670ac0db5SEtienne Carriere out:
147770ac0db5SEtienne Carriere *count = pin_count;
147870ac0db5SEtienne Carriere }
147970ac0db5SEtienne Carriere
1480b38386fbSEtienne Carriere /* Allocate and return a pinctrl configuration from a DT reference */
stm32_pinctrl_dt_get(struct dt_pargs * pargs,void * data __unused,struct pinconf ** out_pinconf)1481b38386fbSEtienne Carriere static TEE_Result stm32_pinctrl_dt_get(struct dt_pargs *pargs,
1482b38386fbSEtienne Carriere void *data __unused,
1483b38386fbSEtienne Carriere struct pinconf **out_pinconf)
1484b38386fbSEtienne Carriere {
1485b38386fbSEtienne Carriere struct conf {
1486b38386fbSEtienne Carriere struct pinconf pinconf;
1487b38386fbSEtienne Carriere struct stm32_pinctrl_array array_ref;
1488b38386fbSEtienne Carriere } *loc_conf = NULL;
1489b38386fbSEtienne Carriere struct stm32_pinctrl *pinctrl = NULL;
1490b38386fbSEtienne Carriere struct pinconf *pinconf = NULL;
1491b38386fbSEtienne Carriere const void *fdt = NULL;
1492b38386fbSEtienne Carriere size_t pin_count = 0;
1493b38386fbSEtienne Carriere int pinctrl_node = 0;
1494b38386fbSEtienne Carriere int pinmux_node = 0;
1495b38386fbSEtienne Carriere int count = 0;
1496b38386fbSEtienne Carriere
1497b38386fbSEtienne Carriere pinctrl_node = pargs->phandle_node;
1498b38386fbSEtienne Carriere fdt = pargs->fdt;
1499b38386fbSEtienne Carriere assert(fdt && pinctrl_node);
1500b38386fbSEtienne Carriere
1501b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1502b38386fbSEtienne Carriere if (fdt_getprop(fdt, pinmux_node, "pinmux", &count))
1503b38386fbSEtienne Carriere pin_count += (size_t)count / sizeof(uint32_t);
1504b38386fbSEtienne Carriere else if (count != -FDT_ERR_NOTFOUND)
1505b38386fbSEtienne Carriere panic();
1506b38386fbSEtienne Carriere }
1507b38386fbSEtienne Carriere
1508b38386fbSEtienne Carriere loc_conf = calloc(1, sizeof(*loc_conf) + sizeof(*pinctrl) * pin_count);
1509b38386fbSEtienne Carriere if (!loc_conf)
1510b38386fbSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY;
1511b38386fbSEtienne Carriere
1512b38386fbSEtienne Carriere pinconf = &loc_conf->pinconf;
1513b38386fbSEtienne Carriere pinconf->ops = &stm32_pinctrl_ops;
1514b38386fbSEtienne Carriere pinconf->priv = &loc_conf->array_ref;
1515b38386fbSEtienne Carriere
1516b38386fbSEtienne Carriere loc_conf->array_ref.count = pin_count;
1517b38386fbSEtienne Carriere pinctrl = loc_conf->array_ref.pinctrl;
1518b38386fbSEtienne Carriere
1519b38386fbSEtienne Carriere count = 0;
1520b38386fbSEtienne Carriere fdt_for_each_subnode(pinmux_node, fdt, pinctrl_node) {
1521b38386fbSEtienne Carriere int found = 0;
1522b38386fbSEtienne Carriere
15235f27da69SEtienne Carriere found = get_pinctrl_from_fdt(fdt, pinmux_node,
15245f27da69SEtienne Carriere pargs->consumer_node,
15255f27da69SEtienne Carriere pinctrl + count,
1526b38386fbSEtienne Carriere pin_count - count);
1527b38386fbSEtienne Carriere if (found <= 0 && found > ((int)pin_count - count)) {
1528b38386fbSEtienne Carriere /* We can't recover from an error here so let's panic */
1529b38386fbSEtienne Carriere panic();
1530b38386fbSEtienne Carriere }
1531b38386fbSEtienne Carriere
1532b38386fbSEtienne Carriere count += found;
1533b38386fbSEtienne Carriere }
1534b38386fbSEtienne Carriere
1535b38386fbSEtienne Carriere *out_pinconf = pinconf;
1536b38386fbSEtienne Carriere
1537b38386fbSEtienne Carriere return TEE_SUCCESS;
1538b38386fbSEtienne Carriere }
1539b38386fbSEtienne Carriere #endif /*CFG_DRIVERS_PINCTRL*/
1540b38386fbSEtienne Carriere
stm32_gpio_get_conf_sec(struct stm32_gpio_bank * bank)1541bfc43b68SGatien Chevallier static void stm32_gpio_get_conf_sec(struct stm32_gpio_bank *bank)
1542bfc43b68SGatien Chevallier {
1543bfc43b68SGatien Chevallier if (bank->sec_support) {
1544bfc43b68SGatien Chevallier clk_enable(bank->clock);
1545bfc43b68SGatien Chevallier bank->seccfgr = io_read32(bank->base + GPIO_SECR_OFFSET);
1546bfc43b68SGatien Chevallier clk_disable(bank->clock);
1547bfc43b68SGatien Chevallier }
1548bfc43b68SGatien Chevallier }
1549bfc43b68SGatien Chevallier
stm32_gpio_set_conf_sec(struct stm32_gpio_bank * bank)1550bd03c8c3SGatien Chevallier static void stm32_gpio_set_conf_sec(struct stm32_gpio_bank *bank)
1551bd03c8c3SGatien Chevallier {
1552bd03c8c3SGatien Chevallier if (bank->sec_support) {
1553bd03c8c3SGatien Chevallier clk_enable(bank->clock);
1554bd03c8c3SGatien Chevallier io_write32(bank->base + GPIO_SECR_OFFSET, bank->seccfgr);
1555bd03c8c3SGatien Chevallier clk_disable(bank->clock);
1556bd03c8c3SGatien Chevallier }
1557bd03c8c3SGatien Chevallier }
1558bd03c8c3SGatien Chevallier
stm32_gpio_sec_config_resume(void)1559bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_resume(void)
1560bfc43b68SGatien Chevallier {
1561bfc43b68SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
1562bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = NULL;
1563bfc43b68SGatien Chevallier
1564bfc43b68SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) {
1565bfc43b68SGatien Chevallier if (bank->rif_cfg) {
1566bfc43b68SGatien Chevallier if (!bank->is_tdcid)
1567bfc43b68SGatien Chevallier continue;
1568bfc43b68SGatien Chevallier
1569bfc43b68SGatien Chevallier bank->rif_cfg->access_mask[0] = GENMASK_32(bank->ngpios,
1570bfc43b68SGatien Chevallier 0);
1571bfc43b68SGatien Chevallier
1572a72f07daSEtienne Carriere res = apply_rif_config(bank,
1573a72f07daSEtienne Carriere bank->rif_cfg->access_mask[0]);
1574bfc43b68SGatien Chevallier if (res) {
1575bfc43b68SGatien Chevallier EMSG("Failed to set GPIO bank %c RIF config",
1576bfc43b68SGatien Chevallier 'A' + bank->bank_id);
1577bfc43b68SGatien Chevallier return res;
1578bfc43b68SGatien Chevallier }
1579bfc43b68SGatien Chevallier } else {
1580bfc43b68SGatien Chevallier stm32_gpio_set_conf_sec(bank);
1581bfc43b68SGatien Chevallier }
1582bfc43b68SGatien Chevallier }
1583bfc43b68SGatien Chevallier
1584bfc43b68SGatien Chevallier return TEE_SUCCESS;
1585bfc43b68SGatien Chevallier }
1586bfc43b68SGatien Chevallier
stm32_gpio_sec_config_suspend(void)1587bfc43b68SGatien Chevallier static TEE_Result stm32_gpio_sec_config_suspend(void)
1588bfc43b68SGatien Chevallier {
1589bfc43b68SGatien Chevallier struct stm32_gpio_bank *bank = NULL;
1590bfc43b68SGatien Chevallier
1591bfc43b68SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) {
1592bfc43b68SGatien Chevallier if (bank->rif_cfg) {
1593bfc43b68SGatien Chevallier if (bank->is_tdcid)
1594bfc43b68SGatien Chevallier stm32_gpio_save_rif_config(bank);
1595bfc43b68SGatien Chevallier } else {
1596bfc43b68SGatien Chevallier stm32_gpio_get_conf_sec(bank);
1597bfc43b68SGatien Chevallier }
1598bfc43b68SGatien Chevallier }
1599bfc43b68SGatien Chevallier
1600bfc43b68SGatien Chevallier return TEE_SUCCESS;
1601bfc43b68SGatien Chevallier }
1602bfc43b68SGatien Chevallier
1603bfc43b68SGatien Chevallier static TEE_Result
stm32_gpio_sec_config_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * hdl __unused)1604bfc43b68SGatien Chevallier stm32_gpio_sec_config_pm(enum pm_op op, unsigned int pm_hint,
1605bfc43b68SGatien Chevallier const struct pm_callback_handle *hdl __unused)
1606bfc43b68SGatien Chevallier {
1607bfc43b68SGatien Chevallier TEE_Result ret = TEE_ERROR_GENERIC;
1608bfc43b68SGatien Chevallier
1609bfc43b68SGatien Chevallier if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
1610bfc43b68SGatien Chevallier return TEE_SUCCESS;
1611bfc43b68SGatien Chevallier
1612bfc43b68SGatien Chevallier if (op == PM_OP_RESUME)
1613bfc43b68SGatien Chevallier ret = stm32_gpio_sec_config_resume();
1614bfc43b68SGatien Chevallier else
1615bfc43b68SGatien Chevallier ret = stm32_gpio_sec_config_suspend();
1616bfc43b68SGatien Chevallier
1617bfc43b68SGatien Chevallier return ret;
1618bfc43b68SGatien Chevallier }
1619bfc43b68SGatien Chevallier DECLARE_KEEP_PAGER(stm32_gpio_sec_config_pm);
1620bfc43b68SGatien Chevallier
1621bd03c8c3SGatien Chevallier /*
1622bd03c8c3SGatien Chevallier * Several pinctrl nodes can be probed. Their bank will be put in the unique
1623bd03c8c3SGatien Chevallier * bank_list. To avoid multiple configuration set for a bank when looping
1624bd03c8c3SGatien Chevallier * over each bank in the bank list, ready is set to true when a bank is
1625bd03c8c3SGatien Chevallier * configured. Therefore, during other bank probes, the configuration won't
1626bd03c8c3SGatien Chevallier * be set again.
1627bd03c8c3SGatien Chevallier */
apply_sec_cfg(void)1628bd03c8c3SGatien Chevallier static TEE_Result apply_sec_cfg(void)
1629bd03c8c3SGatien Chevallier {
1630bd03c8c3SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
1631bd03c8c3SGatien Chevallier struct stm32_gpio_bank *bank = NULL;
1632430c415aSEtienne Carriere unsigned int pin = 0;
1633bd03c8c3SGatien Chevallier
1634bd03c8c3SGatien Chevallier STAILQ_FOREACH(bank, &bank_list, link) {
1635bd03c8c3SGatien Chevallier if (bank->ready)
1636bd03c8c3SGatien Chevallier continue;
1637bd03c8c3SGatien Chevallier
1638bd03c8c3SGatien Chevallier if (bank->rif_cfg) {
1639a72f07daSEtienne Carriere res = apply_rif_config(bank,
1640a72f07daSEtienne Carriere bank->rif_cfg->access_mask[0]);
1641bd03c8c3SGatien Chevallier if (res) {
1642bd03c8c3SGatien Chevallier EMSG("Failed to set GPIO bank %c RIF config",
1643bd03c8c3SGatien Chevallier 'A' + bank->bank_id);
1644bd03c8c3SGatien Chevallier STAILQ_REMOVE(&bank_list, bank, stm32_gpio_bank,
1645bd03c8c3SGatien Chevallier link);
16469def1fb7SGatien Chevallier free(bank);
1647bd03c8c3SGatien Chevallier return res;
1648bd03c8c3SGatien Chevallier }
1649430c415aSEtienne Carriere
1650430c415aSEtienne Carriere /*
1651430c415aSEtienne Carriere * Semaphores for pinctrl and GPIO are taken when
1652430c415aSEtienne Carriere * these are used (pinctrl state applied, GPIO
1653430c415aSEtienne Carriere * consumed) or when an explicit firewall configuration
1654430c415aSEtienne Carriere * is requested through the firewall framework.
1655430c415aSEtienne Carriere * Therefore release here the taken semaphores.
1656430c415aSEtienne Carriere */
1657430c415aSEtienne Carriere for (pin = 0; pin < bank->ngpios; pin++)
1658430c415aSEtienne Carriere release_rif_semaphore_if_acquired(bank, pin);
1659430c415aSEtienne Carriere
1660bd03c8c3SGatien Chevallier } else {
1661bd03c8c3SGatien Chevallier stm32_gpio_set_conf_sec(bank);
1662bd03c8c3SGatien Chevallier }
1663bd03c8c3SGatien Chevallier
1664bd03c8c3SGatien Chevallier bank->ready = true;
1665bd03c8c3SGatien Chevallier }
1666bd03c8c3SGatien Chevallier
1667bd03c8c3SGatien Chevallier return TEE_SUCCESS;
1668bd03c8c3SGatien Chevallier }
1669bd03c8c3SGatien Chevallier
stm32_pinctrl_probe(const void * fdt,int node,const void * compat_data)16700e0435e2SEtienne Carriere static TEE_Result stm32_pinctrl_probe(const void *fdt, int node,
16710e0435e2SEtienne Carriere const void *compat_data)
16720e0435e2SEtienne Carriere {
1673bfc43b68SGatien Chevallier static bool pm_register;
1674b38386fbSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC;
1675b38386fbSEtienne Carriere
16760e0435e2SEtienne Carriere /* Register GPIO banks described in this pin control node */
1677b38386fbSEtienne Carriere res = dt_stm32_gpio_pinctrl(fdt, node, compat_data);
1678b38386fbSEtienne Carriere if (res)
1679b38386fbSEtienne Carriere return res;
1680b38386fbSEtienne Carriere
1681bd03c8c3SGatien Chevallier if (STAILQ_EMPTY(&bank_list))
1682bd03c8c3SGatien Chevallier DMSG("no gpio bank for that driver");
1683bd03c8c3SGatien Chevallier else if (apply_sec_cfg())
1684bd03c8c3SGatien Chevallier panic();
1685bd03c8c3SGatien Chevallier
1686bfc43b68SGatien Chevallier if (!pm_register) {
1687bfc43b68SGatien Chevallier /*
1688bfc43b68SGatien Chevallier * Register to PM once for all probed banks to restore
1689bfc43b68SGatien Chevallier * their secure configuration.
1690bfc43b68SGatien Chevallier */
1691bfc43b68SGatien Chevallier register_pm_driver_cb(stm32_gpio_sec_config_pm, NULL,
1692bfc43b68SGatien Chevallier "stm32-gpio-secure-config");
1693bfc43b68SGatien Chevallier pm_register = true;
1694bfc43b68SGatien Chevallier }
1695bfc43b68SGatien Chevallier
1696b38386fbSEtienne Carriere #ifdef CFG_DRIVERS_PINCTRL
1697b38386fbSEtienne Carriere res = pinctrl_register_provider(fdt, node, stm32_pinctrl_dt_get,
1698b38386fbSEtienne Carriere (void *)compat_data);
1699b38386fbSEtienne Carriere if (res)
1700bd03c8c3SGatien Chevallier panic();
1701b38386fbSEtienne Carriere #endif
1702b38386fbSEtienne Carriere
1703b38386fbSEtienne Carriere return TEE_SUCCESS;
17040e0435e2SEtienne Carriere }
17050e0435e2SEtienne Carriere
17060e0435e2SEtienne Carriere static const struct dt_device_match stm32_pinctrl_match_table[] = {
1707e569f6adSEtienne Carriere {
1708e569f6adSEtienne Carriere .compatible = "st,stm32mp135-pinctrl",
1709b4893304SGatien Chevallier .compat_data = &(struct bank_compat){
1710b4893304SGatien Chevallier .secure_control = true,
1711bd03c8c3SGatien Chevallier .secure_extended = false,
1712b4893304SGatien Chevallier },
1713e569f6adSEtienne Carriere },
1714e569f6adSEtienne Carriere {
1715e569f6adSEtienne Carriere .compatible = "st,stm32mp157-pinctrl",
1716b4893304SGatien Chevallier .compat_data = &(struct bank_compat){
1717b4893304SGatien Chevallier .secure_control = false,
1718bd03c8c3SGatien Chevallier .secure_extended = false,
1719b4893304SGatien Chevallier },
1720e569f6adSEtienne Carriere },
1721e569f6adSEtienne Carriere {
1722e569f6adSEtienne Carriere .compatible = "st,stm32mp157-z-pinctrl",
1723b4893304SGatien Chevallier .compat_data = &(struct bank_compat){
1724b4893304SGatien Chevallier .gpioz = true,
1725b4893304SGatien Chevallier .secure_control = true,
1726bd03c8c3SGatien Chevallier .secure_extended = false,
1727bd03c8c3SGatien Chevallier },
1728bd03c8c3SGatien Chevallier },
1729bd03c8c3SGatien Chevallier {
1730bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-pinctrl",
1731bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){
1732bd03c8c3SGatien Chevallier .secure_control = true,
1733bd03c8c3SGatien Chevallier .secure_extended = true,
1734bd03c8c3SGatien Chevallier },
1735bd03c8c3SGatien Chevallier },
1736bd03c8c3SGatien Chevallier {
1737bd03c8c3SGatien Chevallier .compatible = "st,stm32mp257-z-pinctrl",
1738bd03c8c3SGatien Chevallier .compat_data = &(struct bank_compat){
1739bd03c8c3SGatien Chevallier .gpioz = true,
1740bd03c8c3SGatien Chevallier .secure_control = true,
1741bd03c8c3SGatien Chevallier .secure_extended = true,
1742b4893304SGatien Chevallier },
1743e569f6adSEtienne Carriere },
17440e0435e2SEtienne Carriere { }
17450e0435e2SEtienne Carriere };
17460e0435e2SEtienne Carriere
17470e0435e2SEtienne Carriere DEFINE_DT_DRIVER(stm32_pinctrl_dt_driver) = {
17480e0435e2SEtienne Carriere .name = "stm32_gpio-pinctrl",
17490e0435e2SEtienne Carriere .type = DT_DRIVER_PINCTRL,
17500e0435e2SEtienne Carriere .match_table = stm32_pinctrl_match_table,
17510e0435e2SEtienne Carriere .probe = stm32_pinctrl_probe,
17520e0435e2SEtienne Carriere };
1753