^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // This file is provided under a dual BSD/GPLv2 license. When using or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // redistributing this file, you may do so under either license.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // Copyright(c) 2018 Intel Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "ops.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "sof-priv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "sof-audio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Helper function to determine the target DSP state during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * system suspend. This function only cares about the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * D-states. Platform-specific substates, if any, should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * handled by the platform-specific parts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u32 target_dsp_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) switch (sdev->system_suspend_target) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) case SOF_SUSPEND_S3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /* DSP should be in D3 if the system is suspending to S3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) target_dsp_state = SOF_DSP_PM_D3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) case SOF_SUSPEND_S0IX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Currently, the only criterion for retaining the DSP in D0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * is that there are streams that ignored the suspend trigger.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Additional criteria such Soundwire clock-stop mode and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * device suspend latency considerations will be added later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (snd_sof_stream_suspend_ignored(sdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) target_dsp_state = SOF_DSP_PM_D0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) target_dsp_state = SOF_DSP_PM_D3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* This case would be during runtime suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) target_dsp_state = SOF_DSP_PM_D3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return target_dsp_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct sof_ipc_pm_ctx pm_ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct sof_ipc_reply reply;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) memset(&pm_ctx, 0, sizeof(pm_ctx));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* configure ctx save ipc message */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) pm_ctx.hdr.size = sizeof(pm_ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) pm_ctx.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* send ctx save ipc to dsp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) sizeof(pm_ctx), &reply, sizeof(reply));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static void sof_cache_debugfs(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct snd_sof_dfsentry *dfse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) list_for_each_entry(dfse, &sdev->dfsentry_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* nothing to do if debugfs buffer is not IO mem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (dfse->type == SOF_DFSENTRY_TYPE_BUF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* cache memory that is only accessible in D0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) memcpy_fromio(dfse->cache_buf, dfse->io_mem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) dfse->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int sof_resume(struct device *dev, bool runtime_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct snd_sof_dev *sdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u32 old_state = sdev->dsp_power_state.state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* do nothing if dsp resume callbacks are not set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (!runtime_resume && !sof_ops(sdev)->resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (runtime_resume && !sof_ops(sdev)->runtime_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* DSP was never successfully started, nothing to resume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (sdev->first_boot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * if the runtime_resume flag is set, call the runtime_resume routine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * or else call the system resume routine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (runtime_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ret = snd_sof_dsp_runtime_resume(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ret = snd_sof_dsp_resume(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) "error: failed to power up DSP after resume\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * Nothing further to be done for platforms that support the low power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * D0 substate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (!runtime_resume && sof_ops(sdev)->set_power_state &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) old_state == SOF_DSP_PM_D0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) sdev->fw_state = SOF_FW_BOOT_PREPARE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* load the firmware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ret = snd_sof_load_firmware(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) "error: failed to load DSP firmware after resume %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * Boot the firmware. The FW boot status will be modified
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * in snd_sof_run_firmware() depending on the outcome.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) ret = snd_sof_run_firmware(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) "error: failed to boot DSP firmware after resume %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* resume DMA trace, only need send ipc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ret = snd_sof_init_trace_ipc(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* non fatal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) dev_warn(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) "warning: failed to init trace after resume %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* restore pipelines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) ret = sof_restore_pipelines(sdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) "error: failed to restore pipeline after resume %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* notify DSP of system resume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) "error: ctx_restore ipc error during resume %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static int sof_suspend(struct device *dev, bool runtime_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct snd_sof_dev *sdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) u32 target_state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /* do nothing if dsp suspend callback is not set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (!runtime_suspend && !sof_ops(sdev)->suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) goto suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /* set restore_stream for all streams during system suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (!runtime_suspend) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) ret = sof_set_hw_params_upon_resume(sdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) "error: setting hw_params flag during suspend %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) target_state = snd_sof_dsp_power_target(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /* Skip to platform-specific suspend if DSP is entering D0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (target_state == SOF_DSP_PM_D0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) goto suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* release trace */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) snd_sof_release_trace(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /* cache debugfs contents during runtime suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (runtime_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) sof_cache_debugfs(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* notify DSP of upcoming power down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (ret == -EBUSY || ret == -EAGAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * runtime PM has logic to handle -EBUSY/-EAGAIN so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * pass these errors up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) "error: ctx_save ipc error during suspend %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) } else if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /* FW in unexpected state, continue to power down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) dev_warn(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) "ctx_save ipc error %d, proceeding with suspend\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) suspend:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) /* return if the DSP was not probed successfully */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) /* platform-specific suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (runtime_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) ret = snd_sof_dsp_runtime_suspend(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ret = snd_sof_dsp_suspend(sdev, target_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) "error: failed to power down DSP during suspend %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* Do not reset FW state if DSP is in D0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (target_state == SOF_DSP_PM_D0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /* reset FW state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) sdev->enabled_cores_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /* Notify DSP of upcoming power down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (sof_ops(sdev)->remove)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) int snd_sof_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return sof_suspend(dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) EXPORT_SYMBOL(snd_sof_runtime_suspend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int snd_sof_runtime_idle(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) struct snd_sof_dev *sdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return snd_sof_dsp_runtime_idle(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) EXPORT_SYMBOL(snd_sof_runtime_idle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) int snd_sof_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return sof_resume(dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) EXPORT_SYMBOL(snd_sof_runtime_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) int snd_sof_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return sof_resume(dev, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) EXPORT_SYMBOL(snd_sof_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int snd_sof_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return sof_suspend(dev, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) EXPORT_SYMBOL(snd_sof_suspend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) int snd_sof_prepare(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct snd_sof_dev *sdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) const struct sof_dev_desc *desc = sdev->pdata->desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* will suspend to S3 by default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) sdev->system_suspend_target = SOF_SUSPEND_S3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (!desc->use_acpi_target_states)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) #if defined(CONFIG_ACPI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (acpi_target_system_state() == ACPI_STATE_S0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) sdev->system_suspend_target = SOF_SUSPEND_S0IX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) EXPORT_SYMBOL(snd_sof_prepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) void snd_sof_complete(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct snd_sof_dev *sdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) sdev->system_suspend_target = SOF_SUSPEND_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) EXPORT_SYMBOL(snd_sof_complete);