Skip to content
Open
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
81 changes: 64 additions & 17 deletions drivers/dma/dma_silabs_siwx91x.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/policy.h>
#include <zephyr/types.h>
#include "rsi_rom_udma.h"
#include "rsi_rom_udma_wrapper.h"
Expand Down Expand Up @@ -60,6 +62,18 @@ struct dma_siwx91x_data {
*/
};

static void siwx91x_dma_pm_policy_state_lock_get(const struct device *dev)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the use of *dev in this function?

{
pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
}

static void siwx91x_dma_pm_policy_state_lock_put(const struct device *dev)
{
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
}

static enum dma_xfer_dir siwx91x_transfer_direction(uint32_t dir)
{
if (dir == MEMORY_TO_MEMORY) {
Expand Down Expand Up @@ -482,7 +496,11 @@ static int siwx91x_dma_start(const struct device *dev, uint32_t channel)
return -EINVAL;
}

/* Get the power management policy state lock */
siwx91x_dma_pm_policy_state_lock_get(dev);
Copy link
Member

@Martinhoff-maker Martinhoff-maker Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually implement PM in GPDMA and see one source of error. In the DMA api definition in zephyr, the user can call dma_start on an already started transfer and it should return no error. Then you will get multiple lock and never going to sleep again. I think you need to take the look only if you didn't have an already running DMA on this channel. Btw, this is he same for dma_stop().


if (RSI_UDMA_ChannelEnable(udma_handle, channel) != 0) {
siwx91x_dma_pm_policy_state_lock_put(dev);
return -EINVAL;
}

Expand Down Expand Up @@ -510,6 +528,8 @@ static int siwx91x_dma_stop(const struct device *dev, uint32_t channel)
return -EIO;
}

siwx91x_dma_pm_policy_state_lock_put(dev);

return 0;
}

Expand Down Expand Up @@ -560,8 +580,7 @@ bool siwx91x_dma_chan_filter(const struct device *dev, int channel, void *filter
}
}

/* Function to initialize DMA peripheral */
static int siwx91x_dma_init(const struct device *dev)
static int dma_siwx91x_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct dma_siwx91x_config *cfg = dev->config;
struct dma_siwx91x_data *data = dev->data;
Expand All @@ -573,25 +592,49 @@ static int siwx91x_dma_init(const struct device *dev)
};
int ret;

ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys);
if (ret) {
return ret;
}
switch (action) {
case PM_DEVICE_ACTION_RESUME:
break;
case PM_DEVICE_ACTION_SUSPEND:
break;
case PM_DEVICE_ACTION_TURN_ON:
ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to turn this clock in PM_DEVICE_ACTION_TURN_ON, or this can be done later in PM_DEVICE_ACTION_RESUME?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was discussed to place it here

if (ret < 0 && ret != -EALREADY) {
return ret;
}

udma_handle = UDMAx_Initialize(&udma_resources, udma_resources.desc, NULL,
(uint32_t *)&data->udma_handle);
if (udma_handle != &data->udma_handle) {
return -EINVAL;
udma_handle = UDMAx_Initialize(&udma_resources, udma_resources.desc, NULL,
(uint32_t *)&data->udma_handle);
if (udma_handle != &data->udma_handle) {
return -EINVAL;
}

if (UDMAx_DMAEnable(&udma_resources, udma_handle) != 0) {
return -EBUSY;
}
break;
case PM_DEVICE_ACTION_TURN_OFF:
ret = clock_control_off(cfg->clock_dev, cfg->clock_subsys);
if (ret < 0 && ret != -EALREADY) {
return ret;
}
break;
default:
return -ENOTSUP;
}

return 0;
}

/* Function to initialize DMA peripheral */
static int siwx91x_dma_init(const struct device *dev)
{
const struct dma_siwx91x_config *cfg = dev->config;

/* Connect the DMA interrupt */
cfg->irq_configure();

if (UDMAx_DMAEnable(&udma_resources, udma_handle) != 0) {
return -EBUSY;
}

return 0;
return pm_device_driver_init(dev, dma_siwx91x_pm_action);
}

static void siwx91x_dma_isr(const struct device *dev)
Expand Down Expand Up @@ -639,6 +682,7 @@ static void siwx91x_dma_isr(const struct device *dev)
dev, data->zephyr_channel_info[channel].cb_data, channel, 0);
}
sys_write32(BIT(channel), (mem_addr_t)&cfg->reg->UDMA_DONE_STATUS_REG);
siwx91x_dma_pm_policy_state_lock_put(dev);
} else {
/* Call UDMA ROM IRQ handler. */
ROMAPI_UDMA_WRAPPER_API->uDMAx_IRQHandler(&udma_resources, udma_resources.desc,
Expand Down Expand Up @@ -701,7 +745,10 @@ static DEVICE_API(dma, siwx91x_dma_api) = {
(siwx91x_dma_chan_desc##inst)), \
.irq_configure = siwx91x_dma_irq_configure_##inst, \
}; \
DEVICE_DT_INST_DEFINE(inst, siwx91x_dma_init, NULL, &dma_data_##inst, &dma_cfg_##inst, \
POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, &siwx91x_dma_api);
PM_DEVICE_DT_INST_DEFINE(inst, dma_siwx91x_pm_action); \
DEVICE_DT_INST_DEFINE(inst, siwx91x_dma_init, PM_DEVICE_DT_INST_GET(inst), \
&dma_data_##inst, &dma_cfg_##inst, POST_KERNEL, \
CONFIG_DMA_INIT_PRIORITY, \
&siwx91x_dma_api);

DT_INST_FOREACH_STATUS_OKAY(SIWX91X_DMA_INIT)
4 changes: 4 additions & 0 deletions dts/arm/silabs/siwg917.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@
clocks = <&clock0 SIWX91X_CLK_DMA0>;
#dma-cells = <1>;
dma-channels = <32>;
power-domains = <&siwx91x_soc_pd>;
zephyr,pm-device-runtime-auto;
Comment on lines +307 to +308
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't you think we can also apply it to ulpdma ? in ps4 sleep state, we will have have the same behavior than the HP uDMA (no register retention)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

status = "disabled";
};

Expand All @@ -318,6 +320,8 @@
silabs,sram-region = <&sram_dma1>;
#dma-cells = <1>;
dma-channels = <12>;
power-domains = <&siwx91x_soc_pd>;
zephyr,pm-device-runtime-auto;
status = "disabled";
};

Expand Down