Skip to content

Commit fcd3004

Browse files
mathieuchopstmnashif
authored andcommitted
drivers: pinctrl: stm32: add support for STM32N6 pinctrl
Modify the STM32 pinctrl driver and SoC-specific pinctrl macros to introduce support of the st,stm32n6-pinctrl variant. Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
1 parent f8db993 commit fcd3004

File tree

2 files changed

+122
-2
lines changed

2 files changed

+122
-2
lines changed

drivers/pinctrl/pinctrl_stm32.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <zephyr/init.h>
1010
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
1111
#include <zephyr/drivers/pinctrl.h>
12+
#include <zephyr/pm/device.h>
13+
#include <zephyr/pm/device_runtime.h>
1214
#include <gpio/gpio_stm32.h>
1315

1416
#include <stm32_ll_bus.h>
@@ -225,6 +227,61 @@ static int stm32_pin_configure(uint32_t pin, uint32_t pin_cgf, uint32_t pin_func
225227
return gpio_stm32_configure(port_device, STM32_PIN(pin), pin_cgf, pin_func);
226228
}
227229

230+
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_pinctrl)
231+
static int apply_iosync_configuration(uint32_t port, uint32_t pin, uint32_t pincfg)
232+
{
233+
const struct device *port_device;
234+
const struct gpio_stm32_config *gpio_cfg;
235+
uint32_t piocfgr, delayr, pinbit;
236+
GPIO_TypeDef *gpio_reg;
237+
int ret;
238+
239+
if (port >= gpio_ports_cnt) {
240+
return -EINVAL;
241+
}
242+
243+
port_device = gpio_ports[port];
244+
if (port_device == NULL || !device_is_ready(port_device)) {
245+
return -ENODEV;
246+
}
247+
248+
/**
249+
* For lack of better way, obtain the GPIO base address from the
250+
* device's configuration directly. This *can* be made cleaner
251+
* but would require reworking the GPIO & PINCTRL entirely...
252+
*/
253+
gpio_cfg = port_device->config;
254+
gpio_reg = (GPIO_TypeDef *)gpio_cfg->base;
255+
256+
/* Make sure GPIO clock is enabled */
257+
ret = pm_device_runtime_get(port_device);
258+
if (ret < 0) {
259+
return ret;
260+
}
261+
262+
piocfgr = (pincfg >> STM32_IORETIME_ADVCFGR_SHIFT) & STM32_IORETIME_ADVCFGR_MASK;
263+
delayr = (pincfg >> STM32_IODELAY_LENGTH_SHIFT) & STM32_IODELAY_LENGTH_MASK;
264+
pinbit = BIT(pin);
265+
266+
/**
267+
* Thanks to clever encoding, we don't have to check whether the I/O retiming
268+
* is to be enabled or not; all we need to do is write to the registers where
269+
* everything will fall in place nicely. This can obviously be updated for
270+
* new hardware, if required...
271+
*/
272+
if (pin <= 7) {
273+
LL_GPIO_SetDelayPin_0_7(gpio_reg, pinbit, delayr);
274+
LL_GPIO_SetPIOControlPin_0_7(gpio_reg, pinbit, piocfgr);
275+
} else {
276+
LL_GPIO_SetDelayPin_8_15(gpio_reg, pinbit, delayr);
277+
LL_GPIO_SetPIOControlPin_8_15(gpio_reg, pinbit, piocfgr);
278+
}
279+
280+
/* Release GPIO device since we are done */
281+
return pm_device_runtime_put(port_device);
282+
}
283+
#endif
284+
228285
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
229286
uintptr_t reg)
230287
{
@@ -285,6 +342,16 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
285342
if (ret < 0) {
286343
return ret;
287344
}
345+
346+
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_pinctrl)
347+
ret = apply_iosync_configuration(
348+
STM32_DT_PINMUX_PORT(mux),
349+
STM32_DT_PINMUX_LINE(mux),
350+
pins[i].pincfg);
351+
if (ret < 0) {
352+
return ret;
353+
}
354+
#endif
288355
}
289356

290357
return 0;

soc/st/stm32/common/pinctrl_soc.h

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
#include <zephyr/dt-bindings/pinctrl/stm32-pinctrl.h>
2323
#endif
2424

25+
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_pinctrl)
26+
/* Required for GPIO LL definitions we use */
27+
#include <stm32_ll_gpio.h>
28+
#endif
29+
2530
#ifdef __cplusplus
2631
extern "C" {
2732
#endif
@@ -32,7 +37,7 @@ extern "C" {
3237
typedef struct pinctrl_soc_pin {
3338
/** Pinmux settings (port, pin and function). */
3439
uint32_t pinmux;
35-
/** Pin configuration (bias, drive and slew rate). */
40+
/** Pin configuration (bias, drive, slew rate, I/O retime) */
3641
uint32_t pincfg;
3742
} pinctrl_soc_pin_t;
3843

@@ -55,6 +60,23 @@ typedef struct pinctrl_soc_pin {
5560
#define STM32_OUTPUT_HIGH 0x1
5661
#define STM32_GPIO_OUTPUT 0x1
5762

63+
/**
64+
* @brief Definitions for the various fields related to I/O synchronization
65+
*
66+
* NOTES:
67+
* (1) Series-specific CMSIS and GPIO LL definitions are used here.
68+
* This is OK as long as the macros are never used on series where
69+
* the underlying definitions do not exist.
70+
* (2) I/O delay values definitions from GPIO LL definitions are used
71+
* directly to ensure greater portability to other platforms.
72+
*/
73+
#define STM32_IOSYNC_DELAY_DIRECTION_OUTPUT 0x0
74+
#define STM32_IOSYNC_DELAY_DIRECTION_INPUT GPIO_ADVCFGRL_DLYPATH0
75+
#define STM32_IOSYNC_RETIME_EDGE_RISING 0x0
76+
#define STM32_IOSYNC_RETIME_EDGE_FALLING GPIO_ADVCFGRL_INVCLK0
77+
#define STM32_IOSYNC_RETIME_EDGE_BOTH GPIO_ADVCFGRL_DE0
78+
#define STM32_IOSYNC_RETIME_ENABLE GPIO_ADVCFGRL_RET0
79+
5880
#ifdef CONFIG_SOC_SERIES_STM32F1X
5981
/**
6082
* @brief Utility macro to initialize pincfg field in #pinctrl_pin_t (F1).
@@ -71,6 +93,36 @@ typedef struct pinctrl_soc_pin {
7193
((STM32_OUTPUT_HIGH * DT_PROP(node_id, output_high)) << STM32_ODR_SHIFT) | \
7294
(DT_ENUM_IDX(node_id, slew_rate) << STM32_MODE_OSPEED_SHIFT))
7395
#else
96+
97+
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_pinctrl)
98+
/* Inner helper macro for Z_PINCTRL_STM32_IOSYNC_INIT */
99+
#define Z_PINCTRL_STM32_IOSYNC_INIT_INNER(delay_path, retime_edge, retime_enable, delay_ps) \
100+
((CONCAT(STM32_IOSYNC_DELAY_DIRECTION_, delay_path) << STM32_IODELAY_DIRECTION_SHIFT) | \
101+
((retime_enable) << STM32_IORETIME_ENABLE_SHIFT) | \
102+
(CONCAT(STM32_IOSYNC_RETIME_EDGE_, retime_edge) << STM32_IORETIME_EDGE_SHIFT) | \
103+
(CONCAT(LL_GPIO_DELAY_, delay_ps) << STM32_IODELAY_LENGTH_SHIFT))
104+
105+
/**
106+
* @brief Utility macro to initialize fields of @ref{pinctrl_pin_t}.pincfg
107+
* related to the I/O synchronization feature
108+
*
109+
* @param node_id Pinctrl node identifier
110+
*
111+
* NOTE: a default value for st,retime-edge is specified to ensure the macro expands properly.
112+
* However, this default value is never used, as I/O retiming is not enabled unless the property
113+
* was explicitly specified in Device Tree.
114+
*/
115+
#define Z_PINCTRL_STM32_IOSYNC_INIT(node_id) \
116+
Z_PINCTRL_STM32_IOSYNC_INIT_INNER( \
117+
DT_STRING_UPPER_TOKEN(node_id, st_io_delay_path), \
118+
DT_STRING_UPPER_TOKEN_OR(node_id, st_retime_edge, RISING), \
119+
STM32_IOSYNC_RETIME_ENABLE * DT_NODE_HAS_PROP(node_id, st_retime_edge), \
120+
DT_PROP(node_id, st_io_delay_ps))
121+
#else /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_pinctrl) */
122+
/** Dummy value for series without I/O synchronization feature */
123+
#define Z_PINCTRL_STM32_IOSYNC_INIT(node_id) 0
124+
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_pinctrl) */
125+
74126
/**
75127
* @brief Utility macro to initialize pincfg field in #pinctrl_pin_t (non-F1).
76128
*
@@ -86,7 +138,8 @@ typedef struct pinctrl_soc_pin {
86138
((STM32_OUTPUT_HIGH * DT_PROP(node_id, output_high)) << STM32_ODR_SHIFT) | \
87139
((STM32_GPIO_OUTPUT * DT_PROP(node_id, output_low)) << STM32_MODER_SHIFT) | \
88140
((STM32_GPIO_OUTPUT * DT_PROP(node_id, output_high)) << STM32_MODER_SHIFT) | \
89-
(DT_ENUM_IDX(node_id, slew_rate) << STM32_OSPEEDR_SHIFT))
141+
(DT_ENUM_IDX(node_id, slew_rate) << STM32_OSPEEDR_SHIFT) | \
142+
(Z_PINCTRL_STM32_IOSYNC_INIT(node_id)))
90143
#endif /* CONFIG_SOC_SERIES_STM32F1X */
91144

92145
/**

0 commit comments

Comments
 (0)