Skip to content

Commit 8cac03e

Browse files
committed
ASoC: SOF: Add support for on-demand DSP boot
On system suspend / resume we always power up the DSP and boot the firmware, which is not strictly needed as right after the firmware booted up we power the DSP down again on suspend and we also power it down after resume after some inactivity. Out of caution, add a new platform descriptor flag to enable on-demand DSP boot since this might not work without changes to platform code on certain platforms. With the on-demand dsp boot enabled we will not boot the DSP and firmware up on system or rpm resume, just enable audio subsystem since audio IPs, like HDA and SoundWire might be needed (codecs suspend/resume operation). Only boot up the DSP during the first hw_params() call when the DSP is really going to be needed. In this way we can handle the audio related use cases: normal audio use (rpm suspend/resume) system suspend/resume without active audio system suspend/resume with active audio system suspend/resume without active audio, and audio start before the rpm suspend timeout Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent 7b5df67 commit 8cac03e

9 files changed

Lines changed: 125 additions & 59 deletions

File tree

include/sound/sof.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ struct sof_dev_desc {
159159
/* The platform supports DSPless mode */
160160
bool dspless_mode_supported;
161161

162+
/* On demand DSP booting is possible on the platform */
163+
bool on_demand_dsp_boot;
164+
162165
/* defaults paths for firmware, library and topology files */
163166
const char *default_fw_path[SOF_IPC_TYPE_COUNT];
164167
const char *default_lib_path[SOF_IPC_TYPE_COUNT];

sound/soc/sof/compress.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ static int sof_compr_set_params(struct snd_soc_component *component,
195195
if (sizeof(*pcm) + ext_data_size > sdev->ipc->max_payload_size)
196196
return -EINVAL;
197197

198+
/*
199+
* Make sure that the DSP is booted up, which might not be the
200+
* case if the on-demand DSP boot is used
201+
*/
202+
ret = snd_sof_boot_dsp_firmware(sdev);
203+
if (ret)
204+
return ret;
205+
198206
pcm = kzalloc(sizeof(*pcm) + ext_data_size, GFP_KERNEL);
199207
if (!pcm)
200208
return -ENOMEM;

sound/soc/sof/control.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,12 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
198198
return ret;
199199
}
200200

201-
ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
201+
/* Make sure the DSP/firmware is booted up */
202+
ret = snd_sof_boot_dsp_firmware(sdev);
203+
if (!ret)
204+
ret = tplg_ops->control->bytes_ext_volatile_get(scontrol,
205+
binary_data,
206+
size);
202207

203208
pm_runtime_mark_last_busy(scomp->dev);
204209
err = pm_runtime_put_autosuspend(scomp->dev);

sound/soc/sof/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
694694
mutex_init(&sdev->power_state_access);
695695
mutex_init(&sdev->ipc_client_mutex);
696696
mutex_init(&sdev->client_event_handler_mutex);
697+
mutex_init(&sdev->dsp_fw_boot_mutex);
697698

698699
/* set default timeouts if none provided */
699700
if (plat_data->desc->ipc_timeout == 0)

sound/soc/sof/debug.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,12 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
216216
goto error;
217217
}
218218

219-
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
219+
/* Make sure the DSP/firmware is booted up */
220+
ret = snd_sof_boot_dsp_firmware(sdev);
221+
if (!ret)
222+
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply,
223+
SOF_IPC_MSG_MAX_SIZE);
224+
220225
pm_runtime_mark_last_busy(sdev->dev);
221226
pm_runtime_put_autosuspend(sdev->dev);
222227
if (ret < 0 || reply->rhdr.error < 0) {

sound/soc/sof/ipc3-dtrace.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,12 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
171171
dev_err(sdev->dev, "enabling device failed: %d\n", ret);
172172
goto error;
173173
}
174-
ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
174+
175+
/* Make sure the DSP/firmware is booted up */
176+
ret = snd_sof_boot_dsp_firmware(sdev);
177+
if (!ret)
178+
ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
179+
175180
pm_runtime_mark_last_busy(sdev->dev);
176181
pm_runtime_put_autosuspend(sdev->dev);
177182

sound/soc/sof/pcm.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
137137

138138
spcm_dbg(spcm, substream->stream, "Entry: hw_params\n");
139139

140+
if (!sdev->dspless_mode_selected) {
141+
/*
142+
* Make sure that the DSP is booted up, which might not be the
143+
* case if the on-demand DSP boot is used
144+
*/
145+
ret = snd_sof_boot_dsp_firmware(sdev);
146+
if (ret)
147+
return ret;
148+
}
149+
140150
/*
141151
* Handle repeated calls to hw_params() without free_pcm() in
142152
* between. At least ALSA OSS emulation depends on this.

sound/soc/sof/pm.c

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -70,67 +70,28 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev)
7070
}
7171
#endif
7272

73-
static int sof_resume(struct device *dev, bool runtime_resume)
73+
int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev)
7474
{
75-
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
7675
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
7776
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
78-
u32 old_state = sdev->dsp_power_state.state;
7977
int ret;
8078

81-
/* do nothing if dsp resume callbacks are not set */
82-
if (!runtime_resume && !sof_ops(sdev)->resume)
83-
return 0;
84-
85-
if (runtime_resume && !sof_ops(sdev)->runtime_resume)
86-
return 0;
79+
guard(mutex)(&sdev->dsp_fw_boot_mutex);
8780

88-
/* DSP was never successfully started, nothing to resume */
89-
if (sdev->first_boot)
81+
if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
82+
/* Firmware already booted, just return */
9083
return 0;
91-
92-
/*
93-
* if the runtime_resume flag is set, call the runtime_resume routine
94-
* or else call the system resume routine
95-
*/
96-
if (runtime_resume)
97-
ret = snd_sof_dsp_runtime_resume(sdev);
98-
else
99-
ret = snd_sof_dsp_resume(sdev);
100-
if (ret < 0) {
101-
dev_err(sdev->dev,
102-
"error: failed to power up DSP after resume\n");
103-
return ret;
10484
}
10585

106-
if (sdev->dspless_mode_selected) {
107-
sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
108-
return 0;
109-
}
110-
111-
/*
112-
* Nothing further to be done for platforms that support the low power
113-
* D0 substate. Resume trace and return when resuming from
114-
* low-power D0 substate
115-
*/
116-
if (!runtime_resume && sof_ops(sdev)->set_power_state &&
117-
old_state == SOF_DSP_PM_D0) {
118-
ret = sof_fw_trace_resume(sdev);
119-
if (ret < 0)
120-
/* non fatal */
121-
dev_warn(sdev->dev,
122-
"failed to enable trace after resume %d\n", ret);
123-
return 0;
124-
}
86+
dev_dbg(sdev->dev, "Booting DSP firmware\n");
12587

12688
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
12789

12890
/* load the firmware */
12991
ret = snd_sof_load_firmware(sdev, NULL);
13092
if (ret < 0) {
131-
dev_err(sdev->dev,
132-
"error: failed to load DSP firmware after resume %d\n",
133-
ret);
93+
dev_err(sdev->dev, "%s: failed to load DSP firmware: %d\n",
94+
__func__, ret);
13495
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
13596
return ret;
13697
}
@@ -143,9 +104,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
143104
*/
144105
ret = snd_sof_run_firmware(sdev);
145106
if (ret < 0) {
146-
dev_err(sdev->dev,
147-
"error: failed to boot DSP firmware after resume %d\n",
148-
ret);
107+
dev_err(sdev->dev, "%s: failed to boot DSP firmware: %d\n",
108+
__func__, ret);
149109
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
150110
return ret;
151111
}
@@ -154,16 +114,16 @@ static int sof_resume(struct device *dev, bool runtime_resume)
154114
ret = sof_fw_trace_resume(sdev);
155115
if (ret < 0) {
156116
/* non fatal */
157-
dev_warn(sdev->dev,
158-
"warning: failed to init trace after resume %d\n",
159-
ret);
117+
dev_warn(sdev->dev, "%s: failed to resume trace: %d\n",
118+
__func__, ret);
160119
}
161120

162121
/* restore pipelines */
163122
if (tplg_ops && tplg_ops->set_up_all_pipelines) {
164123
ret = tplg_ops->set_up_all_pipelines(sdev, false);
165124
if (ret < 0) {
166-
dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret);
125+
dev_err(sdev->dev, "%s: failed to restore pipeline: %d\n",
126+
__func__, ret);
167127
goto setup_fail;
168128
}
169129
}
@@ -175,7 +135,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
175135
if (pm_ops && pm_ops->ctx_restore) {
176136
ret = pm_ops->ctx_restore(sdev);
177137
if (ret < 0)
178-
dev_err(sdev->dev, "ctx_restore IPC error during resume: %d\n", ret);
138+
dev_err(sdev->dev, "%s: ctx_restore IPC failed: %d\n",
139+
__func__, ret);
179140
}
180141

181142
setup_fail:
@@ -192,6 +153,67 @@ static int sof_resume(struct device *dev, bool runtime_resume)
192153

193154
return ret;
194155
}
156+
EXPORT_SYMBOL(snd_sof_boot_dsp_firmware);
157+
158+
static int sof_resume(struct device *dev, bool runtime_resume)
159+
{
160+
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
161+
u32 old_state = sdev->dsp_power_state.state;
162+
int ret;
163+
164+
/* do nothing if dsp resume callbacks are not set */
165+
if (!runtime_resume && !sof_ops(sdev)->resume)
166+
return 0;
167+
168+
if (runtime_resume && !sof_ops(sdev)->runtime_resume)
169+
return 0;
170+
171+
/* DSP was never successfully started, nothing to resume */
172+
if (sdev->first_boot)
173+
return 0;
174+
175+
/*
176+
* if the runtime_resume flag is set, call the runtime_resume routine
177+
* or else call the system resume routine
178+
*/
179+
if (runtime_resume)
180+
ret = snd_sof_dsp_runtime_resume(sdev);
181+
else
182+
ret = snd_sof_dsp_resume(sdev);
183+
if (ret < 0) {
184+
dev_err(sdev->dev,
185+
"error: failed to power up DSP after resume\n");
186+
return ret;
187+
}
188+
189+
if (sdev->dspless_mode_selected) {
190+
sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
191+
return 0;
192+
}
193+
194+
/*
195+
* Nothing further to be done for platforms that support the low power
196+
* D0 substate. Resume trace and return when resuming from
197+
* low-power D0 substate
198+
*/
199+
if (!runtime_resume && sof_ops(sdev)->set_power_state &&
200+
old_state == SOF_DSP_PM_D0) {
201+
ret = sof_fw_trace_resume(sdev);
202+
if (ret < 0)
203+
/* non fatal */
204+
dev_warn(sdev->dev,
205+
"failed to enable trace after resume %d\n", ret);
206+
return 0;
207+
}
208+
209+
if (sdev->pdata->desc->on_demand_dsp_boot) {
210+
/* Only change the fw_state to PREPARE but skip booting */
211+
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
212+
return 0;
213+
}
214+
215+
return snd_sof_boot_dsp_firmware(sdev);
216+
}
195217

196218
static int sof_suspend(struct device *dev, bool runtime_suspend)
197219
{
@@ -297,8 +319,12 @@ int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
297319
{
298320
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
299321

300-
/* Notify DSP of upcoming power down */
301-
if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save)
322+
/*
323+
* Notify DSP of upcoming power down only if the firmware has been
324+
* booted up
325+
*/
326+
if (sdev->fw_state == SOF_FW_BOOT_COMPLETE && sof_ops(sdev)->remove &&
327+
pm_ops && pm_ops->ctx_save)
302328
return pm_ops->ctx_save(sdev);
303329

304330
return 0;

sound/soc/sof/sof-priv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,8 @@ struct snd_sof_dev {
591591
wait_queue_head_t boot_wait;
592592
enum sof_fw_state fw_state;
593593
bool first_boot;
594+
/* mutex to protect DSP firmware boot (except initial, probe time boot */
595+
struct mutex dsp_fw_boot_mutex;
594596

595597
/* work queue in case the probe is implemented in two steps */
596598
struct work_struct probe_work;
@@ -717,6 +719,7 @@ int snd_sof_suspend(struct device *dev);
717719
int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev);
718720
int snd_sof_prepare(struct device *dev);
719721
void snd_sof_complete(struct device *dev);
722+
int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev);
720723

721724
void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);
722725

0 commit comments

Comments
 (0)