Skip to content

Commit fc93caf

Browse files
tmlemankv2019i
authored andcommitted
zephyr: Explicitly manage DAI power states during D3 transitions
Zephyr's device power management framework offers two methods for reducing power consumption: Device Runtime Power Management and System-Managed Device Power Management. These methods allow devices to be suspended when idle, either independently or as part of system power state transitions. The framework is designed to minimize power usage with minimal intervention from applications, relying on device drivers to manage the power state transitions of their devices. The SOF firmware uses Zephyr's Device Runtime Power Management for DAIs, where the device driver is responsible for indicating the active or idle state of the device. However, during system-wide power state transitions such as D3 entry and exit, explicit power state management is necessary to maintain audio data integrity and prevent artifacts. In SOF, entry into the D3 power state requires that there be no active audio pipelines. This means that all pipelines must be paused (if not deleted), and while paused DAIs remain powered up, they must be explicitly managed to ensure they are in the correct state for D3 transitions. This patch enhances the SOF firmware's power management by adding static helper functions `suspend_dais()` and `resume_dais()` within `cpu.c`. These functions manage the power states of DAI components explicitly during D3 state transitions, ensuring that DAIs are suspended before the DSP core enters D3 and resumed upon wake-up. By implementing this logic within the SOF firmware, we provide a more integrated and reliable power management process that aligns with the complex requirements of audio DSP workloads. This approach ensures that the SOF firmware can manage DAI power states effectively, complementing Zephyr's device runtime PM framework. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
1 parent 4aaaf9e commit fc93caf

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

zephyr/lib/cpu.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@
1010
* \authors Tomasz Leman <tomasz.m.leman@intel.com>
1111
*/
1212

13+
#include <sof/audio/component.h>
1314
#include <sof/init.h>
1415
#include <sof/lib/cpu.h>
1516
#include <sof/lib/pm_runtime.h>
1617
#include <ipc/topology.h>
18+
#include <module/module/base.h>
1719
#include <rtos/alloc.h>
1820

21+
#include "../audio/copier/copier.h"
22+
1923
/* Zephyr includes */
2024
#include <version.h>
2125
#include <zephyr/kernel.h>
@@ -47,6 +51,66 @@ extern void *global_imr_ram_storage;
4751
#endif
4852

4953
#if CONFIG_PM
54+
#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
55+
/*
56+
* SOF explicitly manages DAI power states to meet the audio-specific requirement
57+
* that all audio pipelines must be paused prior to entering the D3 power state.
58+
* Zephyr's PM framework is designed to suspend devices based on their runtime
59+
* usage, which does not align with the audio pipeline lifecycle managed by SOF.
60+
* During system PM transitions, Zephyr does not automatically handle the suspension
61+
* of DAIs, as it lacks the context of audio pipeline states. Therefore, SOF
62+
* implements additional logic to synchronize DAI states with the DSP core during
63+
* audio pipeline pauses and resumes. This ensures seamless audio performance and
64+
* data integrity across D3 transitions, which is critical for SOF's operation
65+
* and currently outside the scope of Zephyr's device-level PM capabilities.
66+
*/
67+
static void suspend_dais(void)
68+
{
69+
struct ipc_comp_dev *icd;
70+
struct list_item *clist;
71+
struct processing_module *mod;
72+
struct copier_data *cd;
73+
struct dai_data *dd;
74+
75+
list_for_item(clist, &ipc_get()->comp_list) {
76+
icd = container_of(clist, struct ipc_comp_dev, list);
77+
if (icd->type != COMP_TYPE_COMPONENT || dev_comp_type(icd->cd) != SOF_COMP_DAI)
78+
continue;
79+
80+
mod = comp_mod(icd->cd);
81+
cd = module_get_private_data(mod);
82+
dd = cd->dd[0];
83+
if (dai_remove(dd->dai->dev) < 0) {
84+
tr_err(&zephyr_tr, "DAI suspend failed, type %d index %d",
85+
dd->dai->type, dd->dai->index);
86+
}
87+
}
88+
}
89+
90+
static void resume_dais(void)
91+
{
92+
struct ipc_comp_dev *icd;
93+
struct list_item *clist;
94+
struct processing_module *mod;
95+
struct copier_data *cd;
96+
struct dai_data *dd;
97+
98+
list_for_item(clist, &ipc_get()->comp_list) {
99+
icd = container_of(clist, struct ipc_comp_dev, list);
100+
if (icd->type != COMP_TYPE_COMPONENT || dev_comp_type(icd->cd) != SOF_COMP_DAI)
101+
continue;
102+
103+
mod = comp_mod(icd->cd);
104+
cd = module_get_private_data(mod);
105+
dd = cd->dd[0];
106+
if (dai_probe(dd->dai->dev) < 0) {
107+
tr_err(&zephyr_tr, "DAI resume failed, type %d index %d",
108+
dd->dai->type, dd->dai->index);
109+
}
110+
}
111+
}
112+
#endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */
113+
50114
void cpu_notify_state_entry(enum pm_state state)
51115
{
52116
if (!cpu_is_primary(arch_proc_id()))
@@ -80,6 +144,8 @@ void cpu_notify_state_entry(enum pm_state state)
80144
k_panic();
81145
}
82146

147+
/* Suspend all DAI components before entering D3 state. */
148+
suspend_dais();
83149
#endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */
84150
}
85151
}
@@ -99,6 +165,8 @@ void cpu_notify_state_exit(enum pm_state state)
99165
#endif
100166

101167
#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
168+
/* Resume all DAI components after exiting D3 state. */
169+
resume_dais();
102170
/* free global_imr_ram_storage */
103171
rfree(global_imr_ram_storage);
104172
global_imr_ram_storage = NULL;

0 commit comments

Comments
 (0)