-
Notifications
You must be signed in to change notification settings - Fork 8.1k
driver: dma: dma_silabs_siwx91x: Add pm device support for dma driver #94374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
|
@@ -60,6 +62,18 @@ struct dma_siwx91x_data { | |
*/ | ||
}; | ||
|
||
static void siwx91x_dma_pm_policy_state_lock_get(const struct device *dev) | ||
{ | ||
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) { | ||
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} | ||
|
||
|
@@ -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; | ||
} | ||
|
||
|
@@ -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; | ||
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to turn this clock in There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
jerome-pouiller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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); | ||
jerome-pouiller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
static void siwx91x_dma_isr(const struct device *dev) | ||
|
@@ -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, | ||
|
@@ -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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addressed |
||
status = "disabled"; | ||
}; | ||
|
||
|
@@ -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"; | ||
}; | ||
|
||
|
There was a problem hiding this comment.
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?