diff options
author | Mark Brown <broonie@kernel.org> | 2020-03-27 20:29:20 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-03-27 20:29:20 +0300 |
commit | 1c521d7e62262793789845989edca57dea24eb7d (patch) | |
tree | dd891362188494b9d665229696ffb72187998a00 /sound/soc/sof/intel/cnl.c | |
parent | 8e3bb8ec11ed60963dbb70e69cf1a6806489dce3 (diff) | |
parent | 3d2cdb854659851d991f5b8e97e847e3fd240625 (diff) | |
download | linux-1c521d7e62262793789845989edca57dea24eb7d.tar.xz |
Merge branch 'asoc-5.7' into asoc-next
Diffstat (limited to 'sound/soc/sof/intel/cnl.c')
-rw-r--r-- | sound/soc/sof/intel/cnl.c | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 9e2d8afe0535..e427d00eca71 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -65,11 +65,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) hda_dsp_ipc_get_reply(sdev); snd_sof_ipc_reply(sdev, msg); - if (sdev->code_loading) { - sdev->code_loading = 0; - wake_up(&sdev->waitq); - } - cnl_ipc_dsp_done(sdev); spin_unlock_irq(&sdev->ipc_lock); @@ -171,23 +166,48 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + struct sof_ipc_cmd_hdr *hdr; u32 dr = 0; u32 dd = 0; + /* + * Currently the only compact IPC supported is the PM_GATE + * IPC which is used for transitioning the DSP between the + * D0I0 and D0I3 states. And these are sent only during the + * set_power_state() op. Therefore, there will never be a case + * that a compact IPC results in the DSP exiting D0I3 without + * the host and FW being in sync. + */ if (cnl_compact_ipc_compress(msg, &dr, &dd)) { /* send the message via IPC registers */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, dd); snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, CNL_DSP_REG_HIPCIDR_BUSY | dr); - } else { - /* send the message via mailbox */ - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, - CNL_DSP_REG_HIPCIDR_BUSY); + return 0; } + /* send the message via mailbox */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + CNL_DSP_REG_HIPCIDR_BUSY); + + hdr = msg->msg_data; + + /* + * Use mod_delayed_work() to schedule the delayed work + * to avoid scheduling multiple workqueue items when + * IPCs are sent at a high-rate. mod_delayed_work() + * modifies the timer if the work is pending. + * Also, a new delayed work should not be queued after the + * the CTX_SAVE IPC, which is sent before the DSP enters D3. + */ + if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) + mod_delayed_work(system_wq, &hdev->d0i3_work, + msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS)); + return 0; } @@ -259,6 +279,15 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) + /* probe callbacks */ + .probe_assign = hda_probe_compr_assign, + .probe_free = hda_probe_compr_free, + .probe_set_params = hda_probe_compr_set_params, + .probe_trigger = hda_probe_compr_trigger, + .probe_pointer = hda_probe_compr_pointer, +#endif + /* firmware loading */ .load_firmware = snd_sof_load_firmware_raw, |