root/sound/soc/sof/core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_sof_find_spcm_name
  2. snd_sof_find_spcm_comp
  3. snd_sof_find_spcm_pcm_id
  4. snd_sof_find_swidget
  5. snd_sof_find_swidget_sname
  6. snd_sof_find_dai
  7. snd_sof_get_status
  8. snd_sof_create_page_table
  9. sof_machine_check
  10. sof_probe_continue
  11. sof_probe_work
  12. snd_sof_device_probe
  13. snd_sof_device_remove

   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 <asm/unaligned.h>
  14 #include <sound/soc.h>
  15 #include <sound/sof.h>
  16 #include "sof-priv.h"
  17 #include "ops.h"
  18 
  19 /* SOF defaults if not provided by the platform in ms */
  20 #define TIMEOUT_DEFAULT_IPC_MS  500
  21 #define TIMEOUT_DEFAULT_BOOT_MS 2000
  22 
  23 /*
  24  * Generic object lookup APIs.
  25  */
  26 
  27 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev,
  28                                            const char *name)
  29 {
  30         struct snd_sof_pcm *spcm;
  31 
  32         list_for_each_entry(spcm, &sdev->pcm_list, list) {
  33                 /* match with PCM dai name */
  34                 if (strcmp(spcm->pcm.dai_name, name) == 0)
  35                         return spcm;
  36 
  37                 /* match with playback caps name if set */
  38                 if (*spcm->pcm.caps[0].name &&
  39                     !strcmp(spcm->pcm.caps[0].name, name))
  40                         return spcm;
  41 
  42                 /* match with capture caps name if set */
  43                 if (*spcm->pcm.caps[1].name &&
  44                     !strcmp(spcm->pcm.caps[1].name, name))
  45                         return spcm;
  46         }
  47 
  48         return NULL;
  49 }
  50 
  51 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
  52                                            unsigned int comp_id,
  53                                            int *direction)
  54 {
  55         struct snd_sof_pcm *spcm;
  56 
  57         list_for_each_entry(spcm, &sdev->pcm_list, list) {
  58                 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) {
  59                         *direction = SNDRV_PCM_STREAM_PLAYBACK;
  60                         return spcm;
  61                 }
  62                 if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) {
  63                         *direction = SNDRV_PCM_STREAM_CAPTURE;
  64                         return spcm;
  65                 }
  66         }
  67 
  68         return NULL;
  69 }
  70 
  71 struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
  72                                              unsigned int pcm_id)
  73 {
  74         struct snd_sof_pcm *spcm;
  75 
  76         list_for_each_entry(spcm, &sdev->pcm_list, list) {
  77                 if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
  78                         return spcm;
  79         }
  80 
  81         return NULL;
  82 }
  83 
  84 struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev,
  85                                             const char *name)
  86 {
  87         struct snd_sof_widget *swidget;
  88 
  89         list_for_each_entry(swidget, &sdev->widget_list, list) {
  90                 if (strcmp(name, swidget->widget->name) == 0)
  91                         return swidget;
  92         }
  93 
  94         return NULL;
  95 }
  96 
  97 /* find widget by stream name and direction */
  98 struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev,
  99                                                   const char *pcm_name, int dir)
 100 {
 101         struct snd_sof_widget *swidget;
 102         enum snd_soc_dapm_type type;
 103 
 104         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 105                 type = snd_soc_dapm_aif_in;
 106         else
 107                 type = snd_soc_dapm_aif_out;
 108 
 109         list_for_each_entry(swidget, &sdev->widget_list, list) {
 110                 if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type)
 111                         return swidget;
 112         }
 113 
 114         return NULL;
 115 }
 116 
 117 struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
 118                                      const char *name)
 119 {
 120         struct snd_sof_dai *dai;
 121 
 122         list_for_each_entry(dai, &sdev->dai_list, list) {
 123                 if (dai->name && (strcmp(name, dai->name) == 0))
 124                         return dai;
 125         }
 126 
 127         return NULL;
 128 }
 129 
 130 /*
 131  * FW Panic/fault handling.
 132  */
 133 
 134 struct sof_panic_msg {
 135         u32 id;
 136         const char *msg;
 137 };
 138 
 139 /* standard FW panic types */
 140 static const struct sof_panic_msg panic_msg[] = {
 141         {SOF_IPC_PANIC_MEM, "out of memory"},
 142         {SOF_IPC_PANIC_WORK, "work subsystem init failed"},
 143         {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"},
 144         {SOF_IPC_PANIC_ARCH, "arch init failed"},
 145         {SOF_IPC_PANIC_PLATFORM, "platform init failed"},
 146         {SOF_IPC_PANIC_TASK, "scheduler init failed"},
 147         {SOF_IPC_PANIC_EXCEPTION, "runtime exception"},
 148         {SOF_IPC_PANIC_DEADLOCK, "deadlock"},
 149         {SOF_IPC_PANIC_STACK, "stack overflow"},
 150         {SOF_IPC_PANIC_IDLE, "can't enter idle"},
 151         {SOF_IPC_PANIC_WFI, "invalid wait state"},
 152         {SOF_IPC_PANIC_ASSERT, "assertion failed"},
 153 };
 154 
 155 /*
 156  * helper to be called from .dbg_dump callbacks. No error code is
 157  * provided, it's left as an exercise for the caller of .dbg_dump
 158  * (typically IPC or loader)
 159  */
 160 void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
 161                         u32 tracep_code, void *oops,
 162                         struct sof_ipc_panic_info *panic_info,
 163                         void *stack, size_t stack_words)
 164 {
 165         u32 code;
 166         int i;
 167 
 168         /* is firmware dead ? */
 169         if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) {
 170                 dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n",
 171                         panic_code, tracep_code);
 172                 return; /* no fault ? */
 173         }
 174 
 175         code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK);
 176 
 177         for (i = 0; i < ARRAY_SIZE(panic_msg); i++) {
 178                 if (panic_msg[i].id == code) {
 179                         dev_err(sdev->dev, "error: %s\n", panic_msg[i].msg);
 180                         dev_err(sdev->dev, "error: trace point %8.8x\n",
 181                                 tracep_code);
 182                         goto out;
 183                 }
 184         }
 185 
 186         /* unknown error */
 187         dev_err(sdev->dev, "error: unknown reason %8.8x\n", panic_code);
 188         dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code);
 189 
 190 out:
 191         dev_err(sdev->dev, "error: panic at %s:%d\n",
 192                 panic_info->filename, panic_info->linenum);
 193         sof_oops(sdev, oops);
 194         sof_stack(sdev, oops, stack, stack_words);
 195 }
 196 EXPORT_SYMBOL(snd_sof_get_status);
 197 
 198 /*
 199  * Generic buffer page table creation.
 200  * Take the each physical page address and drop the least significant unused
 201  * bits from each (based on PAGE_SIZE). Then pack valid page address bits
 202  * into compressed page table.
 203  */
 204 
 205 int snd_sof_create_page_table(struct snd_sof_dev *sdev,
 206                               struct snd_dma_buffer *dmab,
 207                               unsigned char *page_table, size_t size)
 208 {
 209         int i, pages;
 210 
 211         pages = snd_sgbuf_aligned_pages(size);
 212 
 213         dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n",
 214                 dmab->area, size, pages);
 215 
 216         for (i = 0; i < pages; i++) {
 217                 /*
 218                  * The number of valid address bits for each page is 20.
 219                  * idx determines the byte position within page_table
 220                  * where the current page's address is stored
 221                  * in the compressed page_table.
 222                  * This can be calculated by multiplying the page number by 2.5.
 223                  */
 224                 u32 idx = (5 * i) >> 1;
 225                 u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
 226                 u8 *pg_table;
 227 
 228                 dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
 229 
 230                 pg_table = (u8 *)(page_table + idx);
 231 
 232                 /*
 233                  * pagetable compression:
 234                  * byte 0     byte 1     byte 2     byte 3     byte 4     byte 5
 235                  * ___________pfn 0__________ __________pfn 1___________  _pfn 2...
 236                  * .... ....  .... ....  .... ....  .... ....  .... ....  ....
 237                  * It is created by:
 238                  * 1. set current location to 0, PFN index i to 0
 239                  * 2. put pfn[i] at current location in Little Endian byte order
 240                  * 3. calculate an intermediate value as
 241                  *    x = (pfn[i+1] << 4) | (pfn[i] & 0xf)
 242                  * 4. put x at offset (current location + 2) in LE byte order
 243                  * 5. increment current location by 5 bytes, increment i by 2
 244                  * 6. continue to (2)
 245                  */
 246                 if (i & 1)
 247                         put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4,
 248                                            pg_table);
 249                 else
 250                         put_unaligned_le32(pfn, pg_table);
 251         }
 252 
 253         return pages;
 254 }
 255 
 256 /*
 257  * SOF Driver enumeration.
 258  */
 259 static int sof_machine_check(struct snd_sof_dev *sdev)
 260 {
 261         struct snd_sof_pdata *plat_data = sdev->pdata;
 262 #if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
 263         struct snd_soc_acpi_mach *machine;
 264         int ret;
 265 #endif
 266 
 267         if (plat_data->machine)
 268                 return 0;
 269 
 270 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
 271         dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
 272         return -ENODEV;
 273 #else
 274         /* fallback to nocodec mode */
 275         dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n");
 276         machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL);
 277         if (!machine)
 278                 return -ENOMEM;
 279 
 280         ret = sof_nocodec_setup(sdev->dev, plat_data, machine,
 281                                 plat_data->desc, plat_data->desc->ops);
 282         if (ret < 0)
 283                 return ret;
 284 
 285         plat_data->machine = machine;
 286 
 287         return 0;
 288 #endif
 289 }
 290 
 291 /*
 292  *                      FW Boot State Transition Diagram
 293  *
 294  *    +-----------------------------------------------------------------------+
 295  *    |                                                                       |
 296  * ------------------        ------------------                               |
 297  * |                |        |                |                               |
 298  * |   BOOT_FAILED  |        |  READY_FAILED  |-------------------------+     |
 299  * |                |        |                |                         |     |
 300  * ------------------        ------------------                         |     |
 301  *      ^                           ^                                   |     |
 302  *      |                           |                                   |     |
 303  * (FW Boot Timeout)            (FW_READY FAIL)                         |     |
 304  *      |                           |                                   |     |
 305  *      |                           |                                   |     |
 306  * ------------------               |              ------------------   |     |
 307  * |                |               |              |                |   |     |
 308  * |   IN_PROGRESS  |---------------+------------->|    COMPLETE    |   |     |
 309  * |                | (FW Boot OK)   (FW_READY OK) |                |   |     |
 310  * ------------------                              ------------------   |     |
 311  *      ^                                               |               |     |
 312  *      |                                               |               |     |
 313  * (FW Loading OK)                             (System Suspend/Runtime Suspend)
 314  *      |                                               |               |     |
 315  *      |                                               |               |     |
 316  * ------------------           ------------------      |               |     |
 317  * |                |           |                |<-----+               |     |
 318  * |   PREPARE      |           |   NOT_STARTED  |<---------------------+     |
 319  * |                |           |                |<---------------------------+
 320  * ------------------           ------------------
 321  *    |     ^                       |      ^
 322  *    |     |                       |      |
 323  *    |     +-----------------------+      |
 324  *    |         (DSP Probe OK)             |
 325  *    |                                    |
 326  *    |                                    |
 327  *    +------------------------------------+
 328  *      (System Suspend/Runtime Suspend)
 329  */
 330 
 331 static int sof_probe_continue(struct snd_sof_dev *sdev)
 332 {
 333         struct snd_sof_pdata *plat_data = sdev->pdata;
 334         const char *drv_name;
 335         const void *mach;
 336         int size;
 337         int ret;
 338 
 339         /* probe the DSP hardware */
 340         ret = snd_sof_probe(sdev);
 341         if (ret < 0) {
 342                 dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
 343                 return ret;
 344         }
 345 
 346         sdev->fw_state = SOF_FW_BOOT_PREPARE;
 347 
 348         /* check machine info */
 349         ret = sof_machine_check(sdev);
 350         if (ret < 0) {
 351                 dev_err(sdev->dev, "error: failed to get machine info %d\n",
 352                         ret);
 353                 goto dbg_err;
 354         }
 355 
 356         /* set up platform component driver */
 357         snd_sof_new_platform_drv(sdev);
 358 
 359         /* register any debug/trace capabilities */
 360         ret = snd_sof_dbg_init(sdev);
 361         if (ret < 0) {
 362                 /*
 363                  * debugfs issues are suppressed in snd_sof_dbg_init() since
 364                  * we cannot rely on debugfs
 365                  * here we trap errors due to memory allocation only.
 366                  */
 367                 dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n",
 368                         ret);
 369                 goto dbg_err;
 370         }
 371 
 372         /* init the IPC */
 373         sdev->ipc = snd_sof_ipc_init(sdev);
 374         if (!sdev->ipc) {
 375                 dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret);
 376                 goto ipc_err;
 377         }
 378 
 379         /* load the firmware */
 380         ret = snd_sof_load_firmware(sdev);
 381         if (ret < 0) {
 382                 dev_err(sdev->dev, "error: failed to load DSP firmware %d\n",
 383                         ret);
 384                 goto fw_load_err;
 385         }
 386 
 387         sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS;
 388 
 389         /*
 390          * Boot the firmware. The FW boot status will be modified
 391          * in snd_sof_run_firmware() depending on the outcome.
 392          */
 393         ret = snd_sof_run_firmware(sdev);
 394         if (ret < 0) {
 395                 dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n",
 396                         ret);
 397                 goto fw_run_err;
 398         }
 399 
 400         /* init DMA trace */
 401         ret = snd_sof_init_trace(sdev);
 402         if (ret < 0) {
 403                 /* non fatal */
 404                 dev_warn(sdev->dev,
 405                          "warning: failed to initialize trace %d\n", ret);
 406         }
 407 
 408         /* hereafter all FW boot flows are for PM reasons */
 409         sdev->first_boot = false;
 410 
 411         /* now register audio DSP platform driver and dai */
 412         ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv,
 413                                               sof_ops(sdev)->drv,
 414                                               sof_ops(sdev)->num_drv);
 415         if (ret < 0) {
 416                 dev_err(sdev->dev,
 417                         "error: failed to register DSP DAI driver %d\n", ret);
 418                 goto fw_trace_err;
 419         }
 420 
 421         drv_name = plat_data->machine->drv_name;
 422         mach = (const void *)plat_data->machine;
 423         size = sizeof(*plat_data->machine);
 424 
 425         /* register machine driver, pass machine info as pdata */
 426         plat_data->pdev_mach =
 427                 platform_device_register_data(sdev->dev, drv_name,
 428                                               PLATFORM_DEVID_NONE, mach, size);
 429 
 430         if (IS_ERR(plat_data->pdev_mach)) {
 431                 ret = PTR_ERR(plat_data->pdev_mach);
 432                 goto fw_trace_err;
 433         }
 434 
 435         dev_dbg(sdev->dev, "created machine %s\n",
 436                 dev_name(&plat_data->pdev_mach->dev));
 437 
 438         if (plat_data->sof_probe_complete)
 439                 plat_data->sof_probe_complete(sdev->dev);
 440 
 441         return 0;
 442 
 443 fw_trace_err:
 444         snd_sof_free_trace(sdev);
 445 fw_run_err:
 446         snd_sof_fw_unload(sdev);
 447 fw_load_err:
 448         snd_sof_ipc_free(sdev);
 449 ipc_err:
 450         snd_sof_free_debug(sdev);
 451 dbg_err:
 452         snd_sof_remove(sdev);
 453 
 454         /* all resources freed, update state to match */
 455         sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
 456         sdev->first_boot = true;
 457 
 458         return ret;
 459 }
 460 
 461 static void sof_probe_work(struct work_struct *work)
 462 {
 463         struct snd_sof_dev *sdev =
 464                 container_of(work, struct snd_sof_dev, probe_work);
 465         int ret;
 466 
 467         ret = sof_probe_continue(sdev);
 468         if (ret < 0) {
 469                 /* errors cannot be propagated, log */
 470                 dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret);
 471         }
 472 }
 473 
 474 int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
 475 {
 476         struct snd_sof_dev *sdev;
 477 
 478         sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
 479         if (!sdev)
 480                 return -ENOMEM;
 481 
 482         /* initialize sof device */
 483         sdev->dev = dev;
 484 
 485         sdev->pdata = plat_data;
 486         sdev->first_boot = true;
 487         sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
 488         dev_set_drvdata(dev, sdev);
 489 
 490         /* check all mandatory ops */
 491         if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run ||
 492             !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
 493             !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
 494             !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params)
 495                 return -EINVAL;
 496 
 497         INIT_LIST_HEAD(&sdev->pcm_list);
 498         INIT_LIST_HEAD(&sdev->kcontrol_list);
 499         INIT_LIST_HEAD(&sdev->widget_list);
 500         INIT_LIST_HEAD(&sdev->dai_list);
 501         INIT_LIST_HEAD(&sdev->route_list);
 502         spin_lock_init(&sdev->ipc_lock);
 503         spin_lock_init(&sdev->hw_lock);
 504 
 505         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
 506                 INIT_WORK(&sdev->probe_work, sof_probe_work);
 507 
 508         /* set default timeouts if none provided */
 509         if (plat_data->desc->ipc_timeout == 0)
 510                 sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS;
 511         else
 512                 sdev->ipc_timeout = plat_data->desc->ipc_timeout;
 513         if (plat_data->desc->boot_timeout == 0)
 514                 sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS;
 515         else
 516                 sdev->boot_timeout = plat_data->desc->boot_timeout;
 517 
 518         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
 519                 schedule_work(&sdev->probe_work);
 520                 return 0;
 521         }
 522 
 523         return sof_probe_continue(sdev);
 524 }
 525 EXPORT_SYMBOL(snd_sof_device_probe);
 526 
 527 int snd_sof_device_remove(struct device *dev)
 528 {
 529         struct snd_sof_dev *sdev = dev_get_drvdata(dev);
 530         struct snd_sof_pdata *pdata = sdev->pdata;
 531 
 532         if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
 533                 cancel_work_sync(&sdev->probe_work);
 534 
 535         if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) {
 536                 snd_sof_fw_unload(sdev);
 537                 snd_sof_ipc_free(sdev);
 538                 snd_sof_free_debug(sdev);
 539                 snd_sof_free_trace(sdev);
 540         }
 541 
 542         /*
 543          * Unregister machine driver. This will unbind the snd_card which
 544          * will remove the component driver and unload the topology
 545          * before freeing the snd_card.
 546          */
 547         if (!IS_ERR_OR_NULL(pdata->pdev_mach))
 548                 platform_device_unregister(pdata->pdev_mach);
 549 
 550         /*
 551          * Unregistering the machine driver results in unloading the topology.
 552          * Some widgets, ex: scheduler, attempt to power down the core they are
 553          * scheduled on, when they are unloaded. Therefore, the DSP must be
 554          * removed only after the topology has been unloaded.
 555          */
 556         if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED)
 557                 snd_sof_remove(sdev);
 558 
 559         /* release firmware */
 560         release_firmware(pdata->fw);
 561         pdata->fw = NULL;
 562 
 563         return 0;
 564 }
 565 EXPORT_SYMBOL(snd_sof_device_remove);
 566 
 567 MODULE_AUTHOR("Liam Girdwood");
 568 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
 569 MODULE_LICENSE("Dual BSD/GPL");
 570 MODULE_ALIAS("platform:sof-audio");

/* [<][>][^][v][top][bottom][index][help] */