Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions doc/services/pm/system.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,16 @@ applications to configure the policy manager to block system from transitioning
into certain power states. This can be used by devices when executing tasks in
background to prevent the system from going to a specific state where it would
lose context.

Some power states above S2RAM may also affect peripheral context; this can lead
to a peripheral losing configuration when certain SoCs enters these specific
low-power states.

These exception states can be described in a peripheral's devicetree node with
the ``reinit-power-states`` property:

.. code-block:: devicetree

device-1 {
reinit-power-states = <&stop2>;
};
52 changes: 51 additions & 1 deletion drivers/serial/uart_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -1955,6 +1955,29 @@ static int uart_stm32_registers_configure(const struct device *dev)
return 0;
}

#ifdef CONFIG_PM
/**
* @brief Reinitialization of UART context
*
* This function reenables clocks, and reconfigures the peripheral registers,
* which is required upon exiting certain low-power modes on select SoCs.
*
* @param direction PM state transition direction
* @param ctx UART device struct
*/
static void uart_stm32_reinit(uint8_t direction, void *ctx)
{
ARG_UNUSED(direction);
const struct device *dev = ctx;

if (uart_stm32_clocks_enable(dev)) {
return;
}

uart_stm32_registers_configure(dev);
}
#endif /* CONFIG_PM */

/**
* @brief Initialize UART channel
*
Expand Down Expand Up @@ -2007,6 +2030,15 @@ static int uart_stm32_init(const struct device *dev)
}
#endif /* CONFIG_PM */

#ifdef CONFIG_PM
if (config->reinit_states_size > 0) {
for (uint8_t i = 0; i < config->reinit_states_size; i++) {
pm_notifier_register(config->notifier, config->reinit_states[i].state,
config->reinit_states[i].substate_id);
}
}
#endif /* CONFIG_PM */

#ifdef CONFIG_UART_ASYNC_API
return uart_stm32_async_init(dev);
#else
Expand Down Expand Up @@ -2162,9 +2194,20 @@ static void uart_stm32_irq_config_func_##index(const struct device *dev) \
.wakeup_line = COND_CODE_1(DT_INST_NODE_HAS_PROP(index, wakeup_line), \
(DT_INST_PROP(index, wakeup_line)), \
(STM32_EXTI_LINE_NONE)),

#define STM32_UART_REINIT_STATES_INIT(index) \
static const struct pm_state_info reinit_states_##index[] \
= PM_STATE_INFO_LIST_FROM_DT_REINIT(DT_DRV_INST(index))

#define STM32_UART_REINIT_CFG_INIT(index) \
.notifier = &PM_NOTIFIER(DT_INST_DEP_ORD(index)), \
.reinit_states = reinit_states_##index, \
.reinit_states_size = ARRAY_SIZE(reinit_states_##index),
#else
#define STM32_UART_PM_WAKEUP(index) /* Not used */
#endif
#define STM32_UART_REINIT_STATES_INIT(index)
#define STM32_UART_REINIT_CFG_INIT(index)
#endif /* CONFIG_PM */

/* Ensure DTS doesn't present an incompatible parity configuration.
* Mark/space parity isn't supported on the STM32 family.
Expand Down Expand Up @@ -2273,10 +2316,16 @@ BUILD_ASSERT( \
#endif

#define STM32_UART_INIT(index) \
\
STM32_UART_IRQ_HANDLER_DECL(index) \
\
PINCTRL_DT_INST_DEFINE(index); \
\
STM32_UART_REINIT_STATES_INIT(index); \
\
PM_NOTIFIER_DEFINE(DT_INST_DEP_ORD(index), PM_STATE_EXIT, \
uart_stm32_reinit, DEVICE_DT_INST_GET(index)); \
\
static const struct stm32_pclken pclken_##index[] = \
STM32_DT_INST_CLOCKS(index);\
\
Expand Down Expand Up @@ -2309,6 +2358,7 @@ static const struct uart_stm32_config uart_stm32_cfg_##index = { \
.de_deassert_time = DT_INST_PROP(index, de_deassert_time), \
.de_invert = DT_INST_PROP(index, de_invert), \
STM32_UART_IRQ_HANDLER_FUNC(index) \
STM32_UART_REINIT_CFG_INIT(index) \
STM32_UART_PM_WAKEUP(index) \
}; \
\
Expand Down
4 changes: 4 additions & 0 deletions drivers/serial/uart_stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/reset.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/pm/pm.h>

#include <stm32_ll_usart.h>

Expand Down Expand Up @@ -59,6 +60,9 @@ struct uart_stm32_config {
/* Device defined as wake-up source */
bool wakeup_source;
uint32_t wakeup_line;
struct pm_notifier *notifier;
const struct pm_state_info *reinit_states;
size_t reinit_states_size;
#endif /* CONFIG_PM */
};

Expand Down
67 changes: 63 additions & 4 deletions drivers/spi/spi_ll_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ LOG_MODULE_REGISTER(spi_ll_stm32);
#include <zephyr/sys/util.h>
#include <zephyr/kernel.h>
#include <soc.h>
#include <stm32_ll_spi.h>
#include <errno.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/pinctrl.h>
Expand Down Expand Up @@ -983,10 +982,8 @@ static inline bool spi_stm32_is_subghzspi(const struct device *dev)
#endif
}

static int spi_stm32_init(const struct device *dev)
static int spi_stm32_clock_configure(const struct spi_stm32_config *cfg)
{
struct spi_stm32_data *data __attribute__((unused)) = dev->data;
const struct spi_stm32_config *cfg = dev->config;
int err;

if (!device_is_ready(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE))) {
Expand All @@ -1011,6 +1008,41 @@ static int spi_stm32_init(const struct device *dev)
}
}

return 0;
}

#ifdef CONFIG_PM
/**
* @brief Reinitialization of SPI context
*
* This function reenables clocks, which is required upon exiting certain
* low-power modes on select SoCs.
*
* @param dev SPI device struct
*
* @return 0
*/
static void spi_stm32_reinit(uint8_t direction, void *ctx)
{
ARG_UNUSED(direction);
const struct device *dev = ctx;
const struct spi_stm32_config *cfg = dev->config;

spi_stm32_clock_configure(cfg);
}
#endif /* CONFIG_PM */

static int spi_stm32_init(const struct device *dev)
{
struct spi_stm32_data *data __attribute__((unused)) = dev->data;
const struct spi_stm32_config *cfg = dev->config;
int err;

err = spi_stm32_clock_configure(cfg);
if (err < 0) {
return err;
}

if (!spi_stm32_is_subghzspi(dev)) {
/* Configure dt provided device signals when available */
err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
Expand Down Expand Up @@ -1048,6 +1080,15 @@ static int spi_stm32_init(const struct device *dev)

spi_context_unlock_unconditionally(&data->ctx);

#ifdef CONFIG_PM
if (cfg->reinit_states_size > 0) {
for (size_t i = 0; i < cfg->reinit_states_size; i++) {
pm_notifier_register(cfg->notifier, cfg->reinit_states[i].state,
cfg->reinit_states[i].substate_id);
}
}
#endif /* CONFIG_PM */

return 0;
}

Expand Down Expand Up @@ -1119,13 +1160,30 @@ static void spi_stm32_irq_config_func_##id(const struct device *dev) \
#define STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id)
#endif

#ifdef CONFIG_PM
#define STM32_SPI_REINIT_STATE_INIT(id) \
static const struct pm_state_info reinit_states_##id[] \
= PM_STATE_INFO_LIST_FROM_DT_REINIT(DT_DRV_INST(id))

#define STM32_SPI_REINIT_CFG_INIT(id) \
.notifier = &PM_NOTIFIER(DT_INST_DEP_ORD(id)), \
.reinit_states = reinit_states_##id, \
.reinit_states_size = ARRAY_SIZE(reinit_states_##id),
#else
#define STM32_SPI_REINIT_STATE_INIT(id)
#define STM32_SPI_REINIT_CFG_INIT(id)
#endif /* CONFIG_PM */

#define STM32_SPI_INIT(id) \
STM32_SPI_IRQ_HANDLER_DECL(id); \
\
PINCTRL_DT_INST_DEFINE(id); \
\
STM32_SPI_REINIT_STATE_INIT(id); \
\
PM_NOTIFIER_DEFINE(DT_INST_DEP_ORD(id), PM_STATE_EXIT, \
spi_stm32_reinit, DEVICE_DT_INST_GET(id)); \
\
static const struct stm32_pclken pclken_##id[] = \
STM32_DT_INST_CLOCKS(id);\
\
Expand All @@ -1136,6 +1194,7 @@ static const struct spi_stm32_config spi_stm32_cfg_##id = { \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
STM32_SPI_IRQ_HANDLER_FUNC(id) \
STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) \
STM32_SPI_REINIT_CFG_INIT(id) \
}; \
\
static struct spi_stm32_data spi_stm32_dev_data_##id = { \
Expand Down
8 changes: 8 additions & 0 deletions drivers/spi/spi_ll_stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#ifndef ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_
#define ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_

#include <zephyr/pm/pm.h>
#include <stm32_ll_spi.h>

#include "spi_context.h"

typedef void (*irq_config_func_t)(const struct device *port);
Expand All @@ -30,6 +33,11 @@ struct spi_stm32_config {
#endif
size_t pclk_len;
const struct stm32_pclken *pclken;
#ifdef CONFIG_PM
struct pm_notifier *notifier;
const struct pm_state_info *reinit_states;
size_t reinit_states_size;
#endif
};

#ifdef CONFIG_SPI_STM32_DMA
Expand Down
5 changes: 5 additions & 0 deletions dts/arm/st/wl/stm32wl.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@
clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>;
resets = <&rctl STM32_RESET(APB2, 14U)>;
interrupts = <36 0>;
reinit-power-states = <&stop2>;
status = "disabled";
};

Expand All @@ -238,6 +239,7 @@
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00020000>;
resets = <&rctl STM32_RESET(APB1L, 17U)>;
interrupts = <37 0>;
reinit-power-states = <&stop2>;
status = "disabled";
};

Expand Down Expand Up @@ -293,6 +295,7 @@
reg = <0x40013000 0x400>;
interrupts = <34 5>;
clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>;
reinit-power-states = <&stop2>;
status = "disabled";
};

Expand All @@ -303,6 +306,7 @@
reg = <0x40003800 0x400>;
interrupts = <35 5>;
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00004000>;
reinit-power-states = <&stop2>;
status = "disabled";
};

Expand All @@ -313,6 +317,7 @@
reg = <0x58010000 0x400>;
interrupts = <44 5>;
clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000001>;
reinit-power-states = <&stop2>;
status = "disabled";
use-subghzspi-nss;

Expand Down
9 changes: 9 additions & 0 deletions dts/bindings/base/pm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@ properties:
description: |
Automatically configure the device for runtime power management after the
init function runs.

reinit-power-states:
type: phandles
description: |
Specifies special power states where a peripheral requires
reinitialization due to configuration loss.

While states at or beyond S2RAM are naturally assumed to need
reinitialization, this property highlights the exceptions to that rule.
Loading