root/sound/soc/sof/pcm.c

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

DEFINITIONS

This source file includes following definitions.
  1. create_page_table
  2. sof_pcm_dsp_params
  3. sof_pcm_period_elapsed_work
  4. snd_sof_pcm_period_elapsed
  5. sof_pcm_hw_params
  6. sof_pcm_dsp_pcm_free
  7. sof_pcm_hw_free
  8. sof_pcm_prepare
  9. sof_pcm_trigger
  10. sof_pcm_pointer
  11. sof_pcm_open
  12. sof_pcm_close
  13. sof_pcm_new
  14. sof_pcm_dai_link_fixup
  15. sof_pcm_probe
  16. sof_pcm_remove
  17. snd_sof_new_platform_drv

   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 // PCM Layer, interface between ALSA and IPC.
  11 //
  12 
  13 #include <linux/pm_runtime.h>
  14 #include <sound/pcm_params.h>
  15 #include <sound/sof.h>
  16 #include "sof-priv.h"
  17 #include "ops.h"
  18 
  19 #define DRV_NAME        "sof-audio-component"
  20 
  21 /* Create DMA buffer page table for DSP */
  22 static int create_page_table(struct snd_pcm_substream *substream,
  23                              unsigned char *dma_area, size_t size)
  24 {
  25         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  26         struct snd_soc_component *component =
  27                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
  28         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
  29         struct snd_sof_pcm *spcm;
  30         struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
  31         int stream = substream->stream;
  32 
  33         spcm = snd_sof_find_spcm_dai(sdev, rtd);
  34         if (!spcm)
  35                 return -EINVAL;
  36 
  37         return snd_sof_create_page_table(sdev, dmab,
  38                 spcm->stream[stream].page_table.area, size);
  39 }
  40 
  41 static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream,
  42                               const struct sof_ipc_pcm_params_reply *reply)
  43 {
  44         struct snd_sof_dev *sdev = spcm->sdev;
  45         /* validate offset */
  46         int ret = snd_sof_ipc_pcm_params(sdev, substream, reply);
  47 
  48         if (ret < 0)
  49                 dev_err(sdev->dev, "error: got wrong reply for PCM %d\n",
  50                         spcm->pcm.pcm_id);
  51 
  52         return ret;
  53 }
  54 
  55 /*
  56  * sof pcm period elapse work
  57  */
  58 static void sof_pcm_period_elapsed_work(struct work_struct *work)
  59 {
  60         struct snd_sof_pcm_stream *sps =
  61                 container_of(work, struct snd_sof_pcm_stream,
  62                              period_elapsed_work);
  63 
  64         snd_pcm_period_elapsed(sps->substream);
  65 }
  66 
  67 /*
  68  * sof pcm period elapse, this could be called at irq thread context.
  69  */
  70 void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
  71 {
  72         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  73         struct snd_soc_component *component =
  74                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
  75         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
  76         struct snd_sof_pcm *spcm;
  77 
  78         spcm = snd_sof_find_spcm_dai(sdev, rtd);
  79         if (!spcm) {
  80                 dev_err(sdev->dev,
  81                         "error: period elapsed for unknown stream!\n");
  82                 return;
  83         }
  84 
  85         /*
  86          * snd_pcm_period_elapsed() can be called in interrupt context
  87          * before IRQ_HANDLED is returned. Inside snd_pcm_period_elapsed(),
  88          * when the PCM is done draining or xrun happened, a STOP IPC will
  89          * then be sent and this IPC will hit IPC timeout.
  90          * To avoid sending IPC before the previous IPC is handled, we
  91          * schedule delayed work here to call the snd_pcm_period_elapsed().
  92          */
  93         schedule_work(&spcm->stream[substream->stream].period_elapsed_work);
  94 }
  95 EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
  96 
  97 /* this may get called several times by oss emulation */
  98 static int sof_pcm_hw_params(struct snd_pcm_substream *substream,
  99                              struct snd_pcm_hw_params *params)
 100 {
 101         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 102         struct snd_pcm_runtime *runtime = substream->runtime;
 103         struct snd_soc_component *component =
 104                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 105         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 106         struct snd_sof_pcm *spcm;
 107         struct sof_ipc_pcm_params pcm;
 108         struct sof_ipc_pcm_params_reply ipc_params_reply;
 109         int ret;
 110 
 111         /* nothing to do for BE */
 112         if (rtd->dai_link->no_pcm)
 113                 return 0;
 114 
 115         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 116         if (!spcm)
 117                 return -EINVAL;
 118 
 119         dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n",
 120                 spcm->pcm.pcm_id, substream->stream);
 121 
 122         memset(&pcm, 0, sizeof(pcm));
 123 
 124         /* allocate audio buffer pages */
 125         ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 126         if (ret < 0) {
 127                 dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n",
 128                         params_buffer_bytes(params), spcm->pcm.pcm_id);
 129                 return ret;
 130         }
 131         if (ret) {
 132                 /*
 133                  * ret == 1 means the buffer is changed
 134                  * create compressed page table for audio firmware
 135                  * ret == 0 means the buffer is not changed
 136                  * so no need to regenerate the page table
 137                  */
 138                 ret = create_page_table(substream, runtime->dma_area,
 139                                         runtime->dma_bytes);
 140                 if (ret < 0)
 141                         return ret;
 142         }
 143 
 144         /* number of pages should be rounded up */
 145         pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes);
 146 
 147         /* set IPC PCM parameters */
 148         pcm.hdr.size = sizeof(pcm);
 149         pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
 150         pcm.comp_id = spcm->stream[substream->stream].comp_id;
 151         pcm.params.hdr.size = sizeof(pcm.params);
 152         pcm.params.buffer.phy_addr =
 153                 spcm->stream[substream->stream].page_table.addr;
 154         pcm.params.buffer.size = runtime->dma_bytes;
 155         pcm.params.direction = substream->stream;
 156         pcm.params.sample_valid_bytes = params_width(params) >> 3;
 157         pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
 158         pcm.params.rate = params_rate(params);
 159         pcm.params.channels = params_channels(params);
 160         pcm.params.host_period_bytes = params_period_bytes(params);
 161 
 162         /* container size */
 163         ret = snd_pcm_format_physical_width(params_format(params));
 164         if (ret < 0)
 165                 return ret;
 166         pcm.params.sample_container_bytes = ret >> 3;
 167 
 168         /* format */
 169         switch (params_format(params)) {
 170         case SNDRV_PCM_FORMAT_S16:
 171                 pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
 172                 break;
 173         case SNDRV_PCM_FORMAT_S24:
 174                 pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
 175                 break;
 176         case SNDRV_PCM_FORMAT_S32:
 177                 pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
 178                 break;
 179         case SNDRV_PCM_FORMAT_FLOAT:
 180                 pcm.params.frame_fmt = SOF_IPC_FRAME_FLOAT;
 181                 break;
 182         default:
 183                 return -EINVAL;
 184         }
 185 
 186         /* firmware already configured host stream */
 187         ret = snd_sof_pcm_platform_hw_params(sdev,
 188                                              substream,
 189                                              params,
 190                                              &pcm.params);
 191         if (ret < 0) {
 192                 dev_err(sdev->dev, "error: platform hw params failed\n");
 193                 return ret;
 194         }
 195 
 196         dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag);
 197 
 198         /* send IPC to the DSP */
 199         ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
 200                                  &ipc_params_reply, sizeof(ipc_params_reply));
 201         if (ret < 0) {
 202                 dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n",
 203                         pcm.params.stream_tag);
 204                 return ret;
 205         }
 206 
 207         ret = sof_pcm_dsp_params(spcm, substream, &ipc_params_reply);
 208         if (ret < 0)
 209                 return ret;
 210 
 211         spcm->prepared[substream->stream] = true;
 212 
 213         /* save pcm hw_params */
 214         memcpy(&spcm->params[substream->stream], params, sizeof(*params));
 215 
 216         return ret;
 217 }
 218 
 219 static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream,
 220                                 struct snd_sof_dev *sdev,
 221                                 struct snd_sof_pcm *spcm)
 222 {
 223         struct sof_ipc_stream stream;
 224         struct sof_ipc_reply reply;
 225         int ret;
 226 
 227         stream.hdr.size = sizeof(stream);
 228         stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
 229         stream.comp_id = spcm->stream[substream->stream].comp_id;
 230 
 231         /* send IPC to the DSP */
 232         ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
 233                                  sizeof(stream), &reply, sizeof(reply));
 234         if (!ret)
 235                 spcm->prepared[substream->stream] = false;
 236 
 237         return ret;
 238 }
 239 
 240 static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
 241 {
 242         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 243         struct snd_soc_component *component =
 244                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 245         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 246         struct snd_sof_pcm *spcm;
 247         int ret, err = 0;
 248 
 249         /* nothing to do for BE */
 250         if (rtd->dai_link->no_pcm)
 251                 return 0;
 252 
 253         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 254         if (!spcm)
 255                 return -EINVAL;
 256 
 257         dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
 258                 substream->stream);
 259 
 260         if (spcm->prepared[substream->stream]) {
 261                 ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
 262                 if (ret < 0)
 263                         err = ret;
 264         }
 265 
 266         snd_pcm_lib_free_pages(substream);
 267 
 268         cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
 269 
 270         ret = snd_sof_pcm_platform_hw_free(sdev, substream);
 271         if (ret < 0) {
 272                 dev_err(sdev->dev, "error: platform hw free failed\n");
 273                 err = ret;
 274         }
 275 
 276         return err;
 277 }
 278 
 279 static int sof_pcm_prepare(struct snd_pcm_substream *substream)
 280 {
 281         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 282         struct snd_soc_component *component =
 283                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 284         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 285         struct snd_sof_pcm *spcm;
 286         int ret;
 287 
 288         /* nothing to do for BE */
 289         if (rtd->dai_link->no_pcm)
 290                 return 0;
 291 
 292         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 293         if (!spcm)
 294                 return -EINVAL;
 295 
 296         if (spcm->prepared[substream->stream])
 297                 return 0;
 298 
 299         dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id,
 300                 substream->stream);
 301 
 302         /* set hw_params */
 303         ret = sof_pcm_hw_params(substream, &spcm->params[substream->stream]);
 304         if (ret < 0) {
 305                 dev_err(sdev->dev, "error: set pcm hw_params after resume\n");
 306                 return ret;
 307         }
 308 
 309         return 0;
 310 }
 311 
 312 /*
 313  * FE dai link trigger actions are always executed in non-atomic context because
 314  * they involve IPC's.
 315  */
 316 static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 317 {
 318         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 319         struct snd_soc_component *component =
 320                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 321         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 322         struct snd_sof_pcm *spcm;
 323         struct sof_ipc_stream stream;
 324         struct sof_ipc_reply reply;
 325         bool reset_hw_params = false;
 326         bool ipc_first = false;
 327         int ret;
 328 
 329         /* nothing to do for BE */
 330         if (rtd->dai_link->no_pcm)
 331                 return 0;
 332 
 333         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 334         if (!spcm)
 335                 return -EINVAL;
 336 
 337         dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n",
 338                 spcm->pcm.pcm_id, substream->stream, cmd);
 339 
 340         stream.hdr.size = sizeof(stream);
 341         stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG;
 342         stream.comp_id = spcm->stream[substream->stream].comp_id;
 343 
 344         switch (cmd) {
 345         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 346                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
 347                 ipc_first = true;
 348                 break;
 349         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 350                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
 351                 break;
 352         case SNDRV_PCM_TRIGGER_RESUME:
 353                 /* set up hw_params */
 354                 ret = sof_pcm_prepare(substream);
 355                 if (ret < 0) {
 356                         dev_err(sdev->dev,
 357                                 "error: failed to set up hw_params upon resume\n");
 358                         return ret;
 359                 }
 360 
 361                 /* fallthrough */
 362         case SNDRV_PCM_TRIGGER_START:
 363                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START;
 364                 break;
 365         case SNDRV_PCM_TRIGGER_SUSPEND:
 366         case SNDRV_PCM_TRIGGER_STOP:
 367                 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
 368                 ipc_first = true;
 369                 reset_hw_params = true;
 370                 break;
 371         default:
 372                 dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd);
 373                 return -EINVAL;
 374         }
 375 
 376         /*
 377          * DMA and IPC sequence is different for start and stop. Need to send
 378          * STOP IPC before stop DMA
 379          */
 380         if (!ipc_first)
 381                 snd_sof_pcm_platform_trigger(sdev, substream, cmd);
 382 
 383         /* send IPC to the DSP */
 384         ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
 385                                  sizeof(stream), &reply, sizeof(reply));
 386 
 387         /* need to STOP DMA even if STOP IPC failed */
 388         if (ipc_first)
 389                 snd_sof_pcm_platform_trigger(sdev, substream, cmd);
 390 
 391         /* free PCM if reset_hw_params is set and the STOP IPC is successful */
 392         if (!ret && reset_hw_params)
 393                 ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
 394 
 395         return ret;
 396 }
 397 
 398 static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream)
 399 {
 400         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 401         struct snd_soc_component *component =
 402                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 403         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 404         struct snd_sof_pcm *spcm;
 405         snd_pcm_uframes_t host, dai;
 406 
 407         /* nothing to do for BE */
 408         if (rtd->dai_link->no_pcm)
 409                 return 0;
 410 
 411         /* use dsp ops pointer callback directly if set */
 412         if (sof_ops(sdev)->pcm_pointer)
 413                 return sof_ops(sdev)->pcm_pointer(sdev, substream);
 414 
 415         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 416         if (!spcm)
 417                 return -EINVAL;
 418 
 419         /* read position from DSP */
 420         host = bytes_to_frames(substream->runtime,
 421                                spcm->stream[substream->stream].posn.host_posn);
 422         dai = bytes_to_frames(substream->runtime,
 423                               spcm->stream[substream->stream].posn.dai_posn);
 424 
 425         dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n",
 426                 spcm->pcm.pcm_id, substream->stream, host, dai);
 427 
 428         return host;
 429 }
 430 
 431 static int sof_pcm_open(struct snd_pcm_substream *substream)
 432 {
 433         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 434         struct snd_pcm_runtime *runtime = substream->runtime;
 435         struct snd_soc_component *component =
 436                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 437         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 438         struct snd_sof_pcm *spcm;
 439         struct snd_soc_tplg_stream_caps *caps;
 440         int ret;
 441 
 442         /* nothing to do for BE */
 443         if (rtd->dai_link->no_pcm)
 444                 return 0;
 445 
 446         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 447         if (!spcm)
 448                 return -EINVAL;
 449 
 450         dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
 451                 substream->stream);
 452 
 453         INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
 454                   sof_pcm_period_elapsed_work);
 455 
 456         caps = &spcm->pcm.caps[substream->stream];
 457 
 458         /* set any runtime constraints based on topology */
 459         snd_pcm_hw_constraint_step(substream->runtime, 0,
 460                                    SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 461                                    le32_to_cpu(caps->period_size_min));
 462         snd_pcm_hw_constraint_step(substream->runtime, 0,
 463                                    SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 464                                    le32_to_cpu(caps->period_size_min));
 465 
 466         /* set runtime config */
 467         runtime->hw.info = SNDRV_PCM_INFO_MMAP |
 468                           SNDRV_PCM_INFO_MMAP_VALID |
 469                           SNDRV_PCM_INFO_INTERLEAVED |
 470                           SNDRV_PCM_INFO_PAUSE |
 471                           SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
 472         runtime->hw.formats = le64_to_cpu(caps->formats);
 473         runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min);
 474         runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max);
 475         runtime->hw.periods_min = le32_to_cpu(caps->periods_min);
 476         runtime->hw.periods_max = le32_to_cpu(caps->periods_max);
 477 
 478         /*
 479          * caps->buffer_size_min is not used since the
 480          * snd_pcm_hardware structure only defines buffer_bytes_max
 481          */
 482         runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
 483 
 484         dev_dbg(sdev->dev, "period min %zd max %zd bytes\n",
 485                 runtime->hw.period_bytes_min,
 486                 runtime->hw.period_bytes_max);
 487         dev_dbg(sdev->dev, "period count %d max %d\n",
 488                 runtime->hw.periods_min,
 489                 runtime->hw.periods_max);
 490         dev_dbg(sdev->dev, "buffer max %zd bytes\n",
 491                 runtime->hw.buffer_bytes_max);
 492 
 493         /* set wait time - TODO: come from topology */
 494         substream->wait_time = 500;
 495 
 496         spcm->stream[substream->stream].posn.host_posn = 0;
 497         spcm->stream[substream->stream].posn.dai_posn = 0;
 498         spcm->stream[substream->stream].substream = substream;
 499         spcm->prepared[substream->stream] = false;
 500 
 501         ret = snd_sof_pcm_platform_open(sdev, substream);
 502         if (ret < 0)
 503                 dev_err(sdev->dev, "error: pcm open failed %d\n", ret);
 504 
 505         return ret;
 506 }
 507 
 508 static int sof_pcm_close(struct snd_pcm_substream *substream)
 509 {
 510         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 511         struct snd_soc_component *component =
 512                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 513         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 514         struct snd_sof_pcm *spcm;
 515         int err;
 516 
 517         /* nothing to do for BE */
 518         if (rtd->dai_link->no_pcm)
 519                 return 0;
 520 
 521         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 522         if (!spcm)
 523                 return -EINVAL;
 524 
 525         dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id,
 526                 substream->stream);
 527 
 528         err = snd_sof_pcm_platform_close(sdev, substream);
 529         if (err < 0) {
 530                 dev_err(sdev->dev, "error: pcm close failed %d\n",
 531                         err);
 532                 /*
 533                  * keep going, no point in preventing the close
 534                  * from happening
 535                  */
 536         }
 537 
 538         return 0;
 539 }
 540 
 541 static struct snd_pcm_ops sof_pcm_ops = {
 542         .open           = sof_pcm_open,
 543         .close          = sof_pcm_close,
 544         .ioctl          = snd_pcm_lib_ioctl,
 545         .hw_params      = sof_pcm_hw_params,
 546         .prepare        = sof_pcm_prepare,
 547         .hw_free        = sof_pcm_hw_free,
 548         .trigger        = sof_pcm_trigger,
 549         .pointer        = sof_pcm_pointer,
 550         .page           = snd_pcm_sgbuf_ops_page,
 551 };
 552 
 553 /*
 554  * Pre-allocate playback/capture audio buffer pages.
 555  * no need to explicitly release memory preallocated by sof_pcm_new in pcm_free
 556  * snd_pcm_lib_preallocate_free_for_all() is called by the core.
 557  */
 558 static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd)
 559 {
 560         struct snd_soc_component *component =
 561                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 562         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 563         struct snd_sof_pcm *spcm;
 564         struct snd_pcm *pcm = rtd->pcm;
 565         struct snd_soc_tplg_stream_caps *caps;
 566         int stream = SNDRV_PCM_STREAM_PLAYBACK;
 567 
 568         /* find SOF PCM for this RTD */
 569         spcm = snd_sof_find_spcm_dai(sdev, rtd);
 570         if (!spcm) {
 571                 dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
 572                          rtd->dai_link->id);
 573                 return 0;
 574         }
 575 
 576         dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
 577 
 578         /* do we need to pre-allocate playback audio buffer pages */
 579         if (!spcm->pcm.playback)
 580                 goto capture;
 581 
 582         caps = &spcm->pcm.caps[stream];
 583 
 584         /* pre-allocate playback audio buffer pages */
 585         dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
 586                 caps->name, caps->buffer_size_min, caps->buffer_size_max);
 587 
 588         snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
 589                                       SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
 590                                       le32_to_cpu(caps->buffer_size_min),
 591                                       le32_to_cpu(caps->buffer_size_max));
 592 capture:
 593         stream = SNDRV_PCM_STREAM_CAPTURE;
 594 
 595         /* do we need to pre-allocate capture audio buffer pages */
 596         if (!spcm->pcm.capture)
 597                 return 0;
 598 
 599         caps = &spcm->pcm.caps[stream];
 600 
 601         /* pre-allocate capture audio buffer pages */
 602         dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
 603                 caps->name, caps->buffer_size_min, caps->buffer_size_max);
 604 
 605         snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
 606                                       SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
 607                                       le32_to_cpu(caps->buffer_size_min),
 608                                       le32_to_cpu(caps->buffer_size_max));
 609 
 610         return 0;
 611 }
 612 
 613 /* fixup the BE DAI link to match any values from topology */
 614 static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
 615                                   struct snd_pcm_hw_params *params)
 616 {
 617         struct snd_interval *rate = hw_param_interval(params,
 618                         SNDRV_PCM_HW_PARAM_RATE);
 619         struct snd_interval *channels = hw_param_interval(params,
 620                                                 SNDRV_PCM_HW_PARAM_CHANNELS);
 621         struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 622         struct snd_soc_component *component =
 623                 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 624         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 625         struct snd_sof_dai *dai =
 626                 snd_sof_find_dai(sdev, (char *)rtd->dai_link->name);
 627 
 628         /* no topology exists for this BE, try a common configuration */
 629         if (!dai) {
 630                 dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n",
 631                          rtd->dai_link->name);
 632 
 633                 /*  set 48k, stereo, 16bits by default */
 634                 rate->min = 48000;
 635                 rate->max = 48000;
 636 
 637                 channels->min = 2;
 638                 channels->max = 2;
 639 
 640                 snd_mask_none(fmt);
 641                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 642 
 643                 return 0;
 644         }
 645 
 646         /* read format from topology */
 647         snd_mask_none(fmt);
 648 
 649         switch (dai->comp_dai.config.frame_fmt) {
 650         case SOF_IPC_FRAME_S16_LE:
 651                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 652                 break;
 653         case SOF_IPC_FRAME_S24_4LE:
 654                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
 655                 break;
 656         case SOF_IPC_FRAME_S32_LE:
 657                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
 658                 break;
 659         default:
 660                 dev_err(sdev->dev, "error: No available DAI format!\n");
 661                 return -EINVAL;
 662         }
 663 
 664         /* read rate and channels from topology */
 665         switch (dai->dai_config->type) {
 666         case SOF_DAI_INTEL_SSP:
 667                 rate->min = dai->dai_config->ssp.fsync_rate;
 668                 rate->max = dai->dai_config->ssp.fsync_rate;
 669                 channels->min = dai->dai_config->ssp.tdm_slots;
 670                 channels->max = dai->dai_config->ssp.tdm_slots;
 671 
 672                 dev_dbg(sdev->dev,
 673                         "rate_min: %d rate_max: %d\n", rate->min, rate->max);
 674                 dev_dbg(sdev->dev,
 675                         "channels_min: %d channels_max: %d\n",
 676                         channels->min, channels->max);
 677 
 678                 break;
 679         case SOF_DAI_INTEL_DMIC:
 680                 /* DMIC only supports 16 or 32 bit formats */
 681                 if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
 682                         dev_err(sdev->dev,
 683                                 "error: invalid fmt %d for DAI type %d\n",
 684                                 dai->comp_dai.config.frame_fmt,
 685                                 dai->dai_config->type);
 686                 }
 687                 break;
 688         case SOF_DAI_INTEL_HDA:
 689                 /* do nothing for HDA dai_link */
 690                 break;
 691         case SOF_DAI_INTEL_ALH:
 692                 /* do nothing for ALH dai_link */
 693                 break;
 694         default:
 695                 dev_err(sdev->dev, "error: invalid DAI type %d\n",
 696                         dai->dai_config->type);
 697                 break;
 698         }
 699 
 700         return 0;
 701 }
 702 
 703 static int sof_pcm_probe(struct snd_soc_component *component)
 704 {
 705         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 706         struct snd_sof_pdata *plat_data = sdev->pdata;
 707         const char *tplg_filename;
 708         int ret;
 709 
 710         /* load the default topology */
 711         sdev->component = component;
 712 
 713         tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
 714                                        "%s/%s",
 715                                        plat_data->tplg_filename_prefix,
 716                                        plat_data->tplg_filename);
 717         if (!tplg_filename)
 718                 return -ENOMEM;
 719 
 720         ret = snd_sof_load_topology(sdev, tplg_filename);
 721         if (ret < 0) {
 722                 dev_err(sdev->dev, "error: failed to load DSP topology %d\n",
 723                         ret);
 724                 return ret;
 725         }
 726 
 727         /*
 728          * Some platforms in SOF, ex: BYT, may not have their platform PM
 729          * callbacks set. Increment the usage count so as to
 730          * prevent the device from entering runtime suspend.
 731          */
 732         if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
 733                 pm_runtime_get_noresume(sdev->dev);
 734 
 735         return ret;
 736 }
 737 
 738 static void sof_pcm_remove(struct snd_soc_component *component)
 739 {
 740         /* remove topology */
 741         snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
 742 }
 743 
 744 void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
 745 {
 746         struct snd_soc_component_driver *pd = &sdev->plat_drv;
 747         struct snd_sof_pdata *plat_data = sdev->pdata;
 748         const char *drv_name;
 749 
 750         drv_name = plat_data->machine->drv_name;
 751 
 752         pd->name = "sof-audio-component";
 753         pd->probe = sof_pcm_probe;
 754         pd->remove = sof_pcm_remove;
 755         pd->ops = &sof_pcm_ops;
 756 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
 757         pd->compr_ops = &sof_compressed_ops;
 758 #endif
 759         pd->pcm_new = sof_pcm_new;
 760         pd->ignore_machine = drv_name;
 761         pd->be_hw_params_fixup = sof_pcm_dai_link_fixup;
 762         pd->be_pcm_base = SOF_BE_PCM_BASE;
 763         pd->use_dai_pcm_id = true;
 764         pd->topology_name_prefix = "sof";
 765 
 766          /* increment module refcount when a pcm is opened */
 767         pd->module_get_upon_open = 1;
 768 }

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