1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2018 Intel Corporation 7 // 8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9 // 10 11 #include <linux/module.h> 12 #include "ops.h" 13 #include "sof-priv.h" 14 #include "sof-audio.h" 15 16 static int override_on_demand_boot = -1; 17 module_param_named(on_demand_boot, override_on_demand_boot, int, 0444); 18 MODULE_PARM_DESC(on_demand_boot, "Force on-demand DSP boot: 0 - disabled, 1 - enabled"); 19 20 /* 21 * Helper function to determine the target DSP state during 22 * system suspend. This function only cares about the device 23 * D-states. Platform-specific substates, if any, should be 24 * handled by the platform-specific parts. 25 */ 26 static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev) 27 { 28 u32 target_dsp_state; 29 30 switch (sdev->system_suspend_target) { 31 case SOF_SUSPEND_S5: 32 case SOF_SUSPEND_S4: 33 /* DSP should be in D3 if the system is suspending to S3+ */ 34 case SOF_SUSPEND_S3: 35 /* DSP should be in D3 if the system is suspending to S3 */ 36 target_dsp_state = SOF_DSP_PM_D3; 37 break; 38 case SOF_SUSPEND_S0IX: 39 /* 40 * Currently, the only criterion for retaining the DSP in D0 41 * is that there are streams that ignored the suspend trigger. 42 * Additional criteria such Soundwire clock-stop mode and 43 * device suspend latency considerations will be added later. 44 */ 45 if (snd_sof_stream_suspend_ignored(sdev)) 46 target_dsp_state = SOF_DSP_PM_D0; 47 else 48 target_dsp_state = SOF_DSP_PM_D3; 49 break; 50 default: 51 /* This case would be during runtime suspend */ 52 target_dsp_state = SOF_DSP_PM_D3; 53 break; 54 } 55 56 return target_dsp_state; 57 } 58 59 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) 60 static void sof_cache_debugfs(struct snd_sof_dev *sdev) 61 { 62 struct snd_sof_dfsentry *dfse; 63 64 list_for_each_entry(dfse, &sdev->dfsentry_list, list) { 65 66 /* nothing to do if debugfs buffer is not IO mem */ 67 if (dfse->type == SOF_DFSENTRY_TYPE_BUF) 68 continue; 69 70 /* cache memory that is only accessible in D0 */ 71 if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) 72 memcpy_fromio(dfse->cache_buf, dfse->io_mem, 73 dfse->size); 74 } 75 } 76 #endif 77 78 int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev) 79 { 80 const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); 81 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 82 int ret; 83 84 guard(mutex)(&sdev->dsp_fw_boot_mutex); 85 86 if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) { 87 /* Firmware already booted, just return */ 88 return 0; 89 } 90 91 dev_dbg(sdev->dev, "Booting DSP firmware\n"); 92 93 sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); 94 95 /* load the firmware */ 96 ret = snd_sof_load_firmware(sdev); 97 if (ret < 0) { 98 dev_err(sdev->dev, "%s: failed to load DSP firmware: %d\n", 99 __func__, ret); 100 sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); 101 return ret; 102 } 103 104 sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS); 105 106 /* 107 * Boot the firmware. The FW boot status will be modified 108 * in snd_sof_run_firmware() depending on the outcome. 109 */ 110 ret = snd_sof_run_firmware(sdev); 111 if (ret < 0) { 112 dev_err(sdev->dev, "%s: failed to boot DSP firmware: %d\n", 113 __func__, ret); 114 sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); 115 return ret; 116 } 117 118 /* resume DMA trace */ 119 ret = sof_fw_trace_resume(sdev); 120 if (ret < 0) { 121 /* non fatal */ 122 dev_warn(sdev->dev, "%s: failed to resume trace: %d\n", 123 __func__, ret); 124 } 125 126 /* restore pipelines */ 127 if (tplg_ops && tplg_ops->set_up_all_pipelines) { 128 ret = tplg_ops->set_up_all_pipelines(sdev, false); 129 if (ret < 0) { 130 dev_err(sdev->dev, "%s: failed to restore pipeline: %d\n", 131 __func__, ret); 132 goto setup_fail; 133 } 134 } 135 136 /* Notify clients not managed by pm framework about core resume */ 137 sof_resume_clients(sdev); 138 139 /* notify DSP of system resume */ 140 if (pm_ops && pm_ops->ctx_restore) { 141 ret = pm_ops->ctx_restore(sdev); 142 if (ret < 0) 143 dev_err(sdev->dev, "%s: ctx_restore IPC failed: %d\n", 144 __func__, ret); 145 } 146 147 setup_fail: 148 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) 149 if (ret < 0) { 150 /* 151 * Debugfs cannot be read in runtime suspend, so cache 152 * the contents upon failure. This allows to capture 153 * possible DSP coredump information. 154 */ 155 sof_cache_debugfs(sdev); 156 } 157 #endif 158 159 return ret; 160 } 161 EXPORT_SYMBOL(snd_sof_boot_dsp_firmware); 162 163 static int sof_resume(struct device *dev, bool runtime_resume) 164 { 165 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 166 u32 old_state = sdev->dsp_power_state.state; 167 bool on_demand_boot; 168 int ret; 169 170 /* do nothing if dsp resume callbacks are not set */ 171 if (!runtime_resume && !sof_ops(sdev)->resume) 172 return 0; 173 174 if (runtime_resume && !sof_ops(sdev)->runtime_resume) 175 return 0; 176 177 /* DSP was never successfully started, nothing to resume */ 178 if (sdev->first_boot) 179 return 0; 180 181 /* 182 * if the runtime_resume flag is set, call the runtime_resume routine 183 * or else call the system resume routine 184 */ 185 if (runtime_resume) 186 ret = snd_sof_dsp_runtime_resume(sdev); 187 else 188 ret = snd_sof_dsp_resume(sdev); 189 if (ret < 0) { 190 dev_err(sdev->dev, 191 "error: failed to power up DSP after resume\n"); 192 return ret; 193 } 194 195 if (sdev->dspless_mode_selected) { 196 sof_set_fw_state(sdev, SOF_DSPLESS_MODE); 197 return 0; 198 } 199 200 /* 201 * Nothing further to be done for platforms that support the low power 202 * D0 substate. Resume trace and return when resuming from 203 * low-power D0 substate 204 */ 205 if (!runtime_resume && sof_ops(sdev)->set_power_state && 206 old_state == SOF_DSP_PM_D0) { 207 ret = sof_fw_trace_resume(sdev); 208 if (ret < 0) 209 /* non fatal */ 210 dev_warn(sdev->dev, 211 "failed to enable trace after resume %d\n", ret); 212 return 0; 213 } 214 215 if (override_on_demand_boot > -1) 216 on_demand_boot = override_on_demand_boot ? true : false; 217 else 218 on_demand_boot = sdev->pdata->desc->on_demand_dsp_boot; 219 220 if (on_demand_boot) { 221 /* Only change the fw_state to PREPARE but skip booting */ 222 sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); 223 return 0; 224 } 225 226 return snd_sof_boot_dsp_firmware(sdev); 227 } 228 229 static int sof_suspend(struct device *dev, bool runtime_suspend) 230 { 231 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 232 const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); 233 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 234 pm_message_t pm_state; 235 u32 target_state = snd_sof_dsp_power_target(sdev); 236 u32 old_state = sdev->dsp_power_state.state; 237 int ret; 238 239 /* do nothing if dsp suspend callback is not set */ 240 if (!runtime_suspend && !sof_ops(sdev)->suspend) 241 return 0; 242 243 if (runtime_suspend && !sof_ops(sdev)->runtime_suspend) 244 return 0; 245 246 /* we need to tear down pipelines only if the DSP hardware is 247 * active, which happens for PCI devices. if the device is 248 * suspended, it is brought back to full power and then 249 * suspended again 250 */ 251 if (tplg_ops && tplg_ops->tear_down_all_pipelines && (old_state == SOF_DSP_PM_D0)) 252 tplg_ops->tear_down_all_pipelines(sdev, false); 253 254 if (sdev->fw_state != SOF_FW_BOOT_COMPLETE) 255 goto suspend; 256 257 /* prepare for streams to be resumed properly upon resume */ 258 if (!runtime_suspend) { 259 ret = snd_sof_dsp_hw_params_upon_resume(sdev); 260 if (ret < 0) { 261 dev_err(sdev->dev, 262 "error: setting hw_params flag during suspend %d\n", 263 ret); 264 return ret; 265 } 266 } 267 268 pm_state.event = target_state; 269 270 /* suspend DMA trace */ 271 sof_fw_trace_suspend(sdev, pm_state); 272 273 /* Notify clients not managed by pm framework about core suspend */ 274 sof_suspend_clients(sdev, pm_state); 275 276 /* Skip to platform-specific suspend if DSP is entering D0 */ 277 if (target_state == SOF_DSP_PM_D0) 278 goto suspend; 279 280 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) 281 /* cache debugfs contents during runtime suspend */ 282 if (runtime_suspend) 283 sof_cache_debugfs(sdev); 284 #endif 285 /* notify DSP of upcoming power down */ 286 if (pm_ops && pm_ops->ctx_save) { 287 ret = pm_ops->ctx_save(sdev); 288 if (ret == -EBUSY || ret == -EAGAIN) { 289 /* 290 * runtime PM has logic to handle -EBUSY/-EAGAIN so 291 * pass these errors up 292 */ 293 dev_err(sdev->dev, "ctx_save IPC error during suspend: %d\n", ret); 294 return ret; 295 } else if (ret < 0) { 296 /* FW in unexpected state, continue to power down */ 297 dev_warn(sdev->dev, "ctx_save IPC error: %d, proceeding with suspend\n", 298 ret); 299 } 300 } 301 302 suspend: 303 304 /* return if the DSP was not probed successfully */ 305 if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED) 306 return 0; 307 308 /* platform-specific suspend */ 309 if (runtime_suspend) 310 ret = snd_sof_dsp_runtime_suspend(sdev); 311 else 312 ret = snd_sof_dsp_suspend(sdev, target_state); 313 if (ret < 0) 314 dev_err(sdev->dev, 315 "error: failed to power down DSP during suspend %d\n", 316 ret); 317 318 /* Do not reset FW state if DSP is in D0 */ 319 if (target_state == SOF_DSP_PM_D0) 320 return ret; 321 322 /* reset FW state */ 323 sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); 324 sdev->enabled_cores_mask = 0; 325 326 return ret; 327 } 328 329 int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev) 330 { 331 const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); 332 333 /* 334 * Notify DSP of upcoming power down only if the firmware has been 335 * booted up 336 */ 337 if (sdev->fw_state == SOF_FW_BOOT_COMPLETE && sof_ops(sdev)->remove && 338 pm_ops && pm_ops->ctx_save) 339 return pm_ops->ctx_save(sdev); 340 341 return 0; 342 } 343 344 int snd_sof_runtime_suspend(struct device *dev) 345 { 346 return sof_suspend(dev, true); 347 } 348 EXPORT_SYMBOL(snd_sof_runtime_suspend); 349 350 int snd_sof_runtime_idle(struct device *dev) 351 { 352 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 353 354 return snd_sof_dsp_runtime_idle(sdev); 355 } 356 EXPORT_SYMBOL(snd_sof_runtime_idle); 357 358 int snd_sof_runtime_resume(struct device *dev) 359 { 360 return sof_resume(dev, true); 361 } 362 EXPORT_SYMBOL(snd_sof_runtime_resume); 363 364 int snd_sof_resume(struct device *dev) 365 { 366 return sof_resume(dev, false); 367 } 368 EXPORT_SYMBOL(snd_sof_resume); 369 370 int snd_sof_suspend(struct device *dev) 371 { 372 return sof_suspend(dev, false); 373 } 374 EXPORT_SYMBOL(snd_sof_suspend); 375 376 int snd_sof_prepare(struct device *dev) 377 { 378 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 379 const struct sof_dev_desc *desc = sdev->pdata->desc; 380 381 /* will suspend to S3 by default */ 382 sdev->system_suspend_target = SOF_SUSPEND_S3; 383 384 /* 385 * if the firmware is crashed or boot failed then we try to aim for S3 386 * to reboot the firmware 387 */ 388 if (sdev->fw_state == SOF_FW_CRASHED || 389 sdev->fw_state == SOF_FW_BOOT_FAILED) 390 return 0; 391 392 if (!desc->use_acpi_target_states) 393 return 0; 394 395 #if defined(CONFIG_ACPI) 396 switch (acpi_target_system_state()) { 397 case ACPI_STATE_S0: 398 sdev->system_suspend_target = SOF_SUSPEND_S0IX; 399 break; 400 case ACPI_STATE_S1: 401 case ACPI_STATE_S2: 402 case ACPI_STATE_S3: 403 sdev->system_suspend_target = SOF_SUSPEND_S3; 404 break; 405 case ACPI_STATE_S4: 406 sdev->system_suspend_target = SOF_SUSPEND_S4; 407 break; 408 case ACPI_STATE_S5: 409 sdev->system_suspend_target = SOF_SUSPEND_S5; 410 break; 411 default: 412 break; 413 } 414 #endif 415 416 return 0; 417 } 418 EXPORT_SYMBOL(snd_sof_prepare); 419 420 void snd_sof_complete(struct device *dev) 421 { 422 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 423 424 sdev->system_suspend_target = SOF_SUSPEND_NONE; 425 } 426 EXPORT_SYMBOL(snd_sof_complete); 427