1 // SPDX-License-Identifier: (GPL-2.0 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. All rights reserved. 7 // 8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9 // 10 11 #include <linux/firmware.h> 12 #include <linux/module.h> 13 #include <sound/soc.h> 14 #include <sound/sof.h> 15 #include "sof-priv.h" 16 #include "ops.h" 17 18 /* see SOF_DBG_ flags */ 19 int sof_core_debug; 20 module_param_named(sof_debug, sof_core_debug, int, 0444); 21 MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); 22 23 /* SOF defaults if not provided by the platform in ms */ 24 #define TIMEOUT_DEFAULT_IPC_MS 500 25 #define TIMEOUT_DEFAULT_BOOT_MS 2000 26 27 /* 28 * Generic object lookup APIs. 29 */ 30 31 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, 32 const char *name) 33 { 34 struct snd_sof_pcm *spcm; 35 36 list_for_each_entry(spcm, &sdev->pcm_list, list) { 37 /* match with PCM dai name */ 38 if (strcmp(spcm->pcm.dai_name, name) == 0) 39 return spcm; 40 41 /* match with playback caps name if set */ 42 if (*spcm->pcm.caps[0].name && 43 !strcmp(spcm->pcm.caps[0].name, name)) 44 return spcm; 45 46 /* match with capture caps name if set */ 47 if (*spcm->pcm.caps[1].name && 48 !strcmp(spcm->pcm.caps[1].name, name)) 49 return spcm; 50 } 51 52 return NULL; 53 } 54 55 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, 56 unsigned int comp_id, 57 int *direction) 58 { 59 struct snd_sof_pcm *spcm; 60 61 list_for_each_entry(spcm, &sdev->pcm_list, list) { 62 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) { 63 *direction = SNDRV_PCM_STREAM_PLAYBACK; 64 return spcm; 65 } 66 if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) { 67 *direction = SNDRV_PCM_STREAM_CAPTURE; 68 return spcm; 69 } 70 } 71 72 return NULL; 73 } 74 75 struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, 76 unsigned int pcm_id) 77 { 78 struct snd_sof_pcm *spcm; 79 80 list_for_each_entry(spcm, &sdev->pcm_list, list) { 81 if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) 82 return spcm; 83 } 84 85 return NULL; 86 } 87 88 struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, 89 const char *name) 90 { 91 struct snd_sof_widget *swidget; 92 93 list_for_each_entry(swidget, &sdev->widget_list, list) { 94 if (strcmp(name, swidget->widget->name) == 0) 95 return swidget; 96 } 97 98 return NULL; 99 } 100 101 /* find widget by stream name and direction */ 102 struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, 103 const char *pcm_name, int dir) 104 { 105 struct snd_sof_widget *swidget; 106 enum snd_soc_dapm_type type; 107 108 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 109 type = snd_soc_dapm_aif_in; 110 else 111 type = snd_soc_dapm_aif_out; 112 113 list_for_each_entry(swidget, &sdev->widget_list, list) { 114 if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type) 115 return swidget; 116 } 117 118 return NULL; 119 } 120 121 struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, 122 const char *name) 123 { 124 struct snd_sof_dai *dai; 125 126 list_for_each_entry(dai, &sdev->dai_list, list) { 127 if (dai->name && (strcmp(name, dai->name) == 0)) 128 return dai; 129 } 130 131 return NULL; 132 } 133 134 bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev) 135 { 136 struct snd_sof_pcm *spcm; 137 138 list_for_each_entry(spcm, &sdev->pcm_list, list) { 139 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || 140 spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) 141 return true; 142 } 143 144 return false; 145 } 146 147 /* 148 * FW Panic/fault handling. 149 */ 150 151 struct sof_panic_msg { 152 u32 id; 153 const char *msg; 154 }; 155 156 /* standard FW panic types */ 157 static const struct sof_panic_msg panic_msg[] = { 158 {SOF_IPC_PANIC_MEM, "out of memory"}, 159 {SOF_IPC_PANIC_WORK, "work subsystem init failed"}, 160 {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"}, 161 {SOF_IPC_PANIC_ARCH, "arch init failed"}, 162 {SOF_IPC_PANIC_PLATFORM, "platform init failed"}, 163 {SOF_IPC_PANIC_TASK, "scheduler init failed"}, 164 {SOF_IPC_PANIC_EXCEPTION, "runtime exception"}, 165 {SOF_IPC_PANIC_DEADLOCK, "deadlock"}, 166 {SOF_IPC_PANIC_STACK, "stack overflow"}, 167 {SOF_IPC_PANIC_IDLE, "can't enter idle"}, 168 {SOF_IPC_PANIC_WFI, "invalid wait state"}, 169 {SOF_IPC_PANIC_ASSERT, "assertion failed"}, 170 }; 171 172 /* 173 * helper to be called from .dbg_dump callbacks. No error code is 174 * provided, it's left as an exercise for the caller of .dbg_dump 175 * (typically IPC or loader) 176 */ 177 void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, 178 u32 tracep_code, void *oops, 179 struct sof_ipc_panic_info *panic_info, 180 void *stack, size_t stack_words) 181 { 182 u32 code; 183 int i; 184 185 /* is firmware dead ? */ 186 if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) { 187 dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n", 188 panic_code, tracep_code); 189 return; /* no fault ? */ 190 } 191 192 code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK); 193 194 for (i = 0; i < ARRAY_SIZE(panic_msg); i++) { 195 if (panic_msg[i].id == code) { 196 dev_err(sdev->dev, "error: %s\n", panic_msg[i].msg); 197 dev_err(sdev->dev, "error: trace point %8.8x\n", 198 tracep_code); 199 goto out; 200 } 201 } 202 203 /* unknown error */ 204 dev_err(sdev->dev, "error: unknown reason %8.8x\n", panic_code); 205 dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code); 206 207 out: 208 dev_err(sdev->dev, "error: panic at %s:%d\n", 209 panic_info->filename, panic_info->linenum); 210 sof_oops(sdev, oops); 211 sof_stack(sdev, oops, stack, stack_words); 212 } 213 EXPORT_SYMBOL(snd_sof_get_status); 214 215 /* 216 * SOF Driver enumeration. 217 */ 218 static int sof_machine_check(struct snd_sof_dev *sdev) 219 { 220 struct snd_sof_pdata *plat_data = sdev->pdata; 221 #if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) 222 struct snd_soc_acpi_mach *machine; 223 int ret; 224 #endif 225 226 if (plat_data->machine) 227 return 0; 228 229 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) 230 dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); 231 return -ENODEV; 232 #else 233 /* fallback to nocodec mode */ 234 dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); 235 machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); 236 if (!machine) 237 return -ENOMEM; 238 239 ret = sof_nocodec_setup(sdev->dev, plat_data, machine, 240 plat_data->desc, plat_data->desc->ops); 241 if (ret < 0) 242 return ret; 243 244 plat_data->machine = machine; 245 246 return 0; 247 #endif 248 } 249 250 static int sof_probe_continue(struct snd_sof_dev *sdev) 251 { 252 struct snd_sof_pdata *plat_data = sdev->pdata; 253 const char *drv_name; 254 const void *mach; 255 int size; 256 int ret; 257 258 /* probe the DSP hardware */ 259 ret = snd_sof_probe(sdev); 260 if (ret < 0) { 261 dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); 262 return ret; 263 } 264 265 /* check machine info */ 266 ret = sof_machine_check(sdev); 267 if (ret < 0) { 268 dev_err(sdev->dev, "error: failed to get machine info %d\n", 269 ret); 270 goto dbg_err; 271 } 272 273 /* set up platform component driver */ 274 snd_sof_new_platform_drv(sdev); 275 276 /* register any debug/trace capabilities */ 277 ret = snd_sof_dbg_init(sdev); 278 if (ret < 0) { 279 /* 280 * debugfs issues are suppressed in snd_sof_dbg_init() since 281 * we cannot rely on debugfs 282 * here we trap errors due to memory allocation only. 283 */ 284 dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n", 285 ret); 286 goto dbg_err; 287 } 288 289 /* init the IPC */ 290 sdev->ipc = snd_sof_ipc_init(sdev); 291 if (!sdev->ipc) { 292 dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret); 293 goto ipc_err; 294 } 295 296 /* load the firmware */ 297 ret = snd_sof_load_firmware(sdev); 298 if (ret < 0) { 299 dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", 300 ret); 301 goto fw_load_err; 302 } 303 304 /* boot the firmware */ 305 ret = snd_sof_run_firmware(sdev); 306 if (ret < 0) { 307 dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n", 308 ret); 309 goto fw_run_err; 310 } 311 312 if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) || 313 (sof_core_debug & SOF_DBG_ENABLE_TRACE)) { 314 sdev->dtrace_is_supported = true; 315 316 /* init DMA trace */ 317 ret = snd_sof_init_trace(sdev); 318 if (ret < 0) { 319 /* non fatal */ 320 dev_warn(sdev->dev, 321 "warning: failed to initialize trace %d\n", 322 ret); 323 } 324 } else { 325 dev_dbg(sdev->dev, "SOF firmware trace disabled\n"); 326 } 327 328 /* hereafter all FW boot flows are for PM reasons */ 329 sdev->first_boot = false; 330 331 /* now register audio DSP platform driver and dai */ 332 ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, 333 sof_ops(sdev)->drv, 334 sof_ops(sdev)->num_drv); 335 if (ret < 0) { 336 dev_err(sdev->dev, 337 "error: failed to register DSP DAI driver %d\n", ret); 338 goto fw_run_err; 339 } 340 341 drv_name = plat_data->machine->drv_name; 342 mach = (const void *)plat_data->machine; 343 size = sizeof(*plat_data->machine); 344 345 /* register machine driver, pass machine info as pdata */ 346 plat_data->pdev_mach = 347 platform_device_register_data(sdev->dev, drv_name, 348 PLATFORM_DEVID_NONE, mach, size); 349 350 if (IS_ERR(plat_data->pdev_mach)) { 351 ret = PTR_ERR(plat_data->pdev_mach); 352 goto fw_run_err; 353 } 354 355 dev_dbg(sdev->dev, "created machine %s\n", 356 dev_name(&plat_data->pdev_mach->dev)); 357 358 /* 359 * Some platforms in SOF, ex: BYT, may not have their platform PM 360 * callbacks set. Increment the usage count so as to 361 * prevent the device from entering runtime suspend. 362 */ 363 if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) 364 pm_runtime_get_noresume(sdev->dev); 365 366 if (plat_data->sof_probe_complete) 367 plat_data->sof_probe_complete(sdev->dev); 368 369 return 0; 370 371 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 372 fw_run_err: 373 snd_sof_fw_unload(sdev); 374 fw_load_err: 375 snd_sof_ipc_free(sdev); 376 ipc_err: 377 snd_sof_free_debug(sdev); 378 dbg_err: 379 snd_sof_remove(sdev); 380 #else 381 382 /* 383 * when the probe_continue is handled in a work queue, the 384 * probe does not fail so we don't release resources here. 385 * They will be released with an explicit call to 386 * snd_sof_device_remove() when the PCI/ACPI device is removed 387 */ 388 389 fw_run_err: 390 fw_load_err: 391 ipc_err: 392 dbg_err: 393 394 #endif 395 396 return ret; 397 } 398 399 static void sof_probe_work(struct work_struct *work) 400 { 401 struct snd_sof_dev *sdev = 402 container_of(work, struct snd_sof_dev, probe_work); 403 int ret; 404 405 ret = sof_probe_continue(sdev); 406 if (ret < 0) { 407 /* errors cannot be propagated, log */ 408 dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret); 409 } 410 } 411 412 int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) 413 { 414 struct snd_sof_dev *sdev; 415 416 sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); 417 if (!sdev) 418 return -ENOMEM; 419 420 /* initialize sof device */ 421 sdev->dev = dev; 422 423 /* initialize default D0 sub-state */ 424 sdev->d0_substate = SOF_DSP_D0I0; 425 426 sdev->pdata = plat_data; 427 sdev->first_boot = true; 428 dev_set_drvdata(dev, sdev); 429 430 /* check all mandatory ops */ 431 if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || 432 !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || 433 !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || 434 !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params || 435 !sof_ops(sdev)->fw_ready) 436 return -EINVAL; 437 438 INIT_LIST_HEAD(&sdev->pcm_list); 439 INIT_LIST_HEAD(&sdev->kcontrol_list); 440 INIT_LIST_HEAD(&sdev->widget_list); 441 INIT_LIST_HEAD(&sdev->dai_list); 442 INIT_LIST_HEAD(&sdev->route_list); 443 spin_lock_init(&sdev->ipc_lock); 444 spin_lock_init(&sdev->hw_lock); 445 446 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) 447 INIT_WORK(&sdev->probe_work, sof_probe_work); 448 449 /* set default timeouts if none provided */ 450 if (plat_data->desc->ipc_timeout == 0) 451 sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; 452 else 453 sdev->ipc_timeout = plat_data->desc->ipc_timeout; 454 if (plat_data->desc->boot_timeout == 0) 455 sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS; 456 else 457 sdev->boot_timeout = plat_data->desc->boot_timeout; 458 459 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) { 460 schedule_work(&sdev->probe_work); 461 return 0; 462 } 463 464 return sof_probe_continue(sdev); 465 } 466 EXPORT_SYMBOL(snd_sof_device_probe); 467 468 int snd_sof_device_remove(struct device *dev) 469 { 470 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 471 struct snd_sof_pdata *pdata = sdev->pdata; 472 473 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) 474 cancel_work_sync(&sdev->probe_work); 475 476 snd_sof_fw_unload(sdev); 477 snd_sof_ipc_free(sdev); 478 snd_sof_free_debug(sdev); 479 snd_sof_free_trace(sdev); 480 481 /* 482 * Unregister machine driver. This will unbind the snd_card which 483 * will remove the component driver and unload the topology 484 * before freeing the snd_card. 485 */ 486 if (!IS_ERR_OR_NULL(pdata->pdev_mach)) 487 platform_device_unregister(pdata->pdev_mach); 488 489 /* 490 * Unregistering the machine driver results in unloading the topology. 491 * Some widgets, ex: scheduler, attempt to power down the core they are 492 * scheduled on, when they are unloaded. Therefore, the DSP must be 493 * removed only after the topology has been unloaded. 494 */ 495 snd_sof_remove(sdev); 496 497 /* release firmware */ 498 release_firmware(pdata->fw); 499 pdata->fw = NULL; 500 501 return 0; 502 } 503 EXPORT_SYMBOL(snd_sof_device_remove); 504 505 MODULE_AUTHOR("Liam Girdwood"); 506 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); 507 MODULE_LICENSE("Dual BSD/GPL"); 508 MODULE_ALIAS("platform:sof-audio"); 509