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 * FW Panic/fault handling. 29 */ 30 31 struct sof_panic_msg { 32 u32 id; 33 const char *msg; 34 }; 35 36 /* standard FW panic types */ 37 static const struct sof_panic_msg panic_msg[] = { 38 {SOF_IPC_PANIC_MEM, "out of memory"}, 39 {SOF_IPC_PANIC_WORK, "work subsystem init failed"}, 40 {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"}, 41 {SOF_IPC_PANIC_ARCH, "arch init failed"}, 42 {SOF_IPC_PANIC_PLATFORM, "platform init failed"}, 43 {SOF_IPC_PANIC_TASK, "scheduler init failed"}, 44 {SOF_IPC_PANIC_EXCEPTION, "runtime exception"}, 45 {SOF_IPC_PANIC_DEADLOCK, "deadlock"}, 46 {SOF_IPC_PANIC_STACK, "stack overflow"}, 47 {SOF_IPC_PANIC_IDLE, "can't enter idle"}, 48 {SOF_IPC_PANIC_WFI, "invalid wait state"}, 49 {SOF_IPC_PANIC_ASSERT, "assertion failed"}, 50 }; 51 52 /* 53 * helper to be called from .dbg_dump callbacks. No error code is 54 * provided, it's left as an exercise for the caller of .dbg_dump 55 * (typically IPC or loader) 56 */ 57 void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, 58 u32 tracep_code, void *oops, 59 struct sof_ipc_panic_info *panic_info, 60 void *stack, size_t stack_words) 61 { 62 u32 code; 63 int i; 64 65 /* is firmware dead ? */ 66 if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) { 67 dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n", 68 panic_code, tracep_code); 69 return; /* no fault ? */ 70 } 71 72 code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK); 73 74 for (i = 0; i < ARRAY_SIZE(panic_msg); i++) { 75 if (panic_msg[i].id == code) { 76 dev_err(sdev->dev, "error: %s\n", panic_msg[i].msg); 77 dev_err(sdev->dev, "error: trace point %8.8x\n", 78 tracep_code); 79 goto out; 80 } 81 } 82 83 /* unknown error */ 84 dev_err(sdev->dev, "error: unknown reason %8.8x\n", panic_code); 85 dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code); 86 87 out: 88 dev_err(sdev->dev, "error: panic at %s:%d\n", 89 panic_info->filename, panic_info->linenum); 90 sof_oops(sdev, oops); 91 sof_stack(sdev, oops, stack, stack_words); 92 } 93 EXPORT_SYMBOL(snd_sof_get_status); 94 95 /* 96 * SOF Driver enumeration. 97 */ 98 static int sof_machine_check(struct snd_sof_dev *sdev) 99 { 100 struct snd_sof_pdata *plat_data = sdev->pdata; 101 #if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) 102 struct snd_soc_acpi_mach *machine; 103 int ret; 104 #endif 105 106 if (plat_data->machine) 107 return 0; 108 109 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) 110 dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); 111 return -ENODEV; 112 #else 113 /* fallback to nocodec mode */ 114 dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); 115 machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); 116 if (!machine) 117 return -ENOMEM; 118 119 ret = sof_nocodec_setup(sdev->dev, plat_data, machine, 120 plat_data->desc, plat_data->desc->ops); 121 if (ret < 0) 122 return ret; 123 124 plat_data->machine = machine; 125 126 return 0; 127 #endif 128 } 129 130 static int sof_probe_continue(struct snd_sof_dev *sdev) 131 { 132 struct snd_sof_pdata *plat_data = sdev->pdata; 133 const char *drv_name; 134 const void *mach; 135 int size; 136 int ret; 137 138 /* probe the DSP hardware */ 139 ret = snd_sof_probe(sdev); 140 if (ret < 0) { 141 dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); 142 return ret; 143 } 144 145 /* check machine info */ 146 ret = sof_machine_check(sdev); 147 if (ret < 0) { 148 dev_err(sdev->dev, "error: failed to get machine info %d\n", 149 ret); 150 goto dbg_err; 151 } 152 153 /* set up platform component driver */ 154 snd_sof_new_platform_drv(sdev); 155 156 /* register any debug/trace capabilities */ 157 ret = snd_sof_dbg_init(sdev); 158 if (ret < 0) { 159 /* 160 * debugfs issues are suppressed in snd_sof_dbg_init() since 161 * we cannot rely on debugfs 162 * here we trap errors due to memory allocation only. 163 */ 164 dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n", 165 ret); 166 goto dbg_err; 167 } 168 169 /* init the IPC */ 170 sdev->ipc = snd_sof_ipc_init(sdev); 171 if (!sdev->ipc) { 172 dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret); 173 goto ipc_err; 174 } 175 176 /* load the firmware */ 177 ret = snd_sof_load_firmware(sdev); 178 if (ret < 0) { 179 dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", 180 ret); 181 goto fw_load_err; 182 } 183 184 /* boot the firmware */ 185 ret = snd_sof_run_firmware(sdev); 186 if (ret < 0) { 187 dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n", 188 ret); 189 goto fw_run_err; 190 } 191 192 if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) || 193 (sof_core_debug & SOF_DBG_ENABLE_TRACE)) { 194 sdev->dtrace_is_supported = true; 195 196 /* init DMA trace */ 197 ret = snd_sof_init_trace(sdev); 198 if (ret < 0) { 199 /* non fatal */ 200 dev_warn(sdev->dev, 201 "warning: failed to initialize trace %d\n", 202 ret); 203 } 204 } else { 205 dev_dbg(sdev->dev, "SOF firmware trace disabled\n"); 206 } 207 208 /* hereafter all FW boot flows are for PM reasons */ 209 sdev->first_boot = false; 210 211 /* now register audio DSP platform driver and dai */ 212 ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, 213 sof_ops(sdev)->drv, 214 sof_ops(sdev)->num_drv); 215 if (ret < 0) { 216 dev_err(sdev->dev, 217 "error: failed to register DSP DAI driver %d\n", ret); 218 goto fw_run_err; 219 } 220 221 drv_name = plat_data->machine->drv_name; 222 mach = (const void *)plat_data->machine; 223 size = sizeof(*plat_data->machine); 224 225 /* register machine driver, pass machine info as pdata */ 226 plat_data->pdev_mach = 227 platform_device_register_data(sdev->dev, drv_name, 228 PLATFORM_DEVID_NONE, mach, size); 229 230 if (IS_ERR(plat_data->pdev_mach)) { 231 ret = PTR_ERR(plat_data->pdev_mach); 232 goto fw_run_err; 233 } 234 235 dev_dbg(sdev->dev, "created machine %s\n", 236 dev_name(&plat_data->pdev_mach->dev)); 237 238 /* 239 * Some platforms in SOF, ex: BYT, may not have their platform PM 240 * callbacks set. Increment the usage count so as to 241 * prevent the device from entering runtime suspend. 242 */ 243 if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) 244 pm_runtime_get_noresume(sdev->dev); 245 246 if (plat_data->sof_probe_complete) 247 plat_data->sof_probe_complete(sdev->dev); 248 249 return 0; 250 251 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 252 fw_run_err: 253 snd_sof_fw_unload(sdev); 254 fw_load_err: 255 snd_sof_ipc_free(sdev); 256 ipc_err: 257 snd_sof_free_debug(sdev); 258 dbg_err: 259 snd_sof_remove(sdev); 260 #else 261 262 /* 263 * when the probe_continue is handled in a work queue, the 264 * probe does not fail so we don't release resources here. 265 * They will be released with an explicit call to 266 * snd_sof_device_remove() when the PCI/ACPI device is removed 267 */ 268 269 fw_run_err: 270 fw_load_err: 271 ipc_err: 272 dbg_err: 273 274 #endif 275 276 return ret; 277 } 278 279 static void sof_probe_work(struct work_struct *work) 280 { 281 struct snd_sof_dev *sdev = 282 container_of(work, struct snd_sof_dev, probe_work); 283 int ret; 284 285 ret = sof_probe_continue(sdev); 286 if (ret < 0) { 287 /* errors cannot be propagated, log */ 288 dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret); 289 } 290 } 291 292 int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) 293 { 294 struct snd_sof_dev *sdev; 295 296 sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); 297 if (!sdev) 298 return -ENOMEM; 299 300 /* initialize sof device */ 301 sdev->dev = dev; 302 303 /* initialize default D0 sub-state */ 304 sdev->d0_substate = SOF_DSP_D0I0; 305 306 sdev->pdata = plat_data; 307 sdev->first_boot = true; 308 dev_set_drvdata(dev, sdev); 309 310 /* check all mandatory ops */ 311 if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || 312 !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || 313 !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || 314 !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params || 315 !sof_ops(sdev)->fw_ready) 316 return -EINVAL; 317 318 INIT_LIST_HEAD(&sdev->pcm_list); 319 INIT_LIST_HEAD(&sdev->kcontrol_list); 320 INIT_LIST_HEAD(&sdev->widget_list); 321 INIT_LIST_HEAD(&sdev->dai_list); 322 INIT_LIST_HEAD(&sdev->route_list); 323 spin_lock_init(&sdev->ipc_lock); 324 spin_lock_init(&sdev->hw_lock); 325 326 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) 327 INIT_WORK(&sdev->probe_work, sof_probe_work); 328 329 /* set default timeouts if none provided */ 330 if (plat_data->desc->ipc_timeout == 0) 331 sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; 332 else 333 sdev->ipc_timeout = plat_data->desc->ipc_timeout; 334 if (plat_data->desc->boot_timeout == 0) 335 sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS; 336 else 337 sdev->boot_timeout = plat_data->desc->boot_timeout; 338 339 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) { 340 schedule_work(&sdev->probe_work); 341 return 0; 342 } 343 344 return sof_probe_continue(sdev); 345 } 346 EXPORT_SYMBOL(snd_sof_device_probe); 347 348 int snd_sof_device_remove(struct device *dev) 349 { 350 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 351 struct snd_sof_pdata *pdata = sdev->pdata; 352 353 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) 354 cancel_work_sync(&sdev->probe_work); 355 356 snd_sof_fw_unload(sdev); 357 snd_sof_ipc_free(sdev); 358 snd_sof_free_debug(sdev); 359 snd_sof_free_trace(sdev); 360 361 /* 362 * Unregister machine driver. This will unbind the snd_card which 363 * will remove the component driver and unload the topology 364 * before freeing the snd_card. 365 */ 366 if (!IS_ERR_OR_NULL(pdata->pdev_mach)) 367 platform_device_unregister(pdata->pdev_mach); 368 369 /* 370 * Unregistering the machine driver results in unloading the topology. 371 * Some widgets, ex: scheduler, attempt to power down the core they are 372 * scheduled on, when they are unloaded. Therefore, the DSP must be 373 * removed only after the topology has been unloaded. 374 */ 375 snd_sof_remove(sdev); 376 377 /* release firmware */ 378 release_firmware(pdata->fw); 379 pdata->fw = NULL; 380 381 return 0; 382 } 383 EXPORT_SYMBOL(snd_sof_device_remove); 384 385 MODULE_AUTHOR("Liam Girdwood"); 386 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); 387 MODULE_LICENSE("Dual BSD/GPL"); 388 MODULE_ALIAS("platform:sof-audio"); 389