linux/sound/soc/sof/pcm.c
<<
>>
Prefs
   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 */
  22static 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
  41static 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 */
  58static 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 */
  70void 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}
  95EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
  96
  97/* this may get called several times by oss emulation */
  98static 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        /* save pcm hw_params */
 212        memcpy(&spcm->params[substream->stream], params, sizeof(*params));
 213
 214        /* clear hw_params_upon_resume flag */
 215        spcm->hw_params_upon_resume[substream->stream] = 0;
 216
 217        return ret;
 218}
 219
 220static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
 221{
 222        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 223        struct snd_soc_component *component =
 224                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 225        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 226        struct snd_sof_pcm *spcm;
 227        struct sof_ipc_stream stream;
 228        struct sof_ipc_reply reply;
 229        int ret;
 230
 231        /* nothing to do for BE */
 232        if (rtd->dai_link->no_pcm)
 233                return 0;
 234
 235        spcm = snd_sof_find_spcm_dai(sdev, rtd);
 236        if (!spcm)
 237                return -EINVAL;
 238
 239        dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
 240                substream->stream);
 241
 242        stream.hdr.size = sizeof(stream);
 243        stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
 244        stream.comp_id = spcm->stream[substream->stream].comp_id;
 245
 246        /* send IPC to the DSP */
 247        ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
 248                                 sizeof(stream), &reply, sizeof(reply));
 249
 250        snd_pcm_lib_free_pages(substream);
 251
 252        cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
 253
 254        if (ret < 0)
 255                return ret;
 256
 257        ret = snd_sof_pcm_platform_hw_free(sdev, substream);
 258        if (ret < 0)
 259                dev_err(sdev->dev, "error: platform hw free failed\n");
 260
 261        return ret;
 262}
 263
 264static int sof_pcm_prepare(struct snd_pcm_substream *substream)
 265{
 266        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 267        struct snd_soc_component *component =
 268                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 269        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 270        struct snd_sof_pcm *spcm;
 271        int ret;
 272
 273        /* nothing to do for BE */
 274        if (rtd->dai_link->no_pcm)
 275                return 0;
 276
 277        spcm = snd_sof_find_spcm_dai(sdev, rtd);
 278        if (!spcm)
 279                return -EINVAL;
 280
 281        /*
 282         * check if hw_params needs to be set-up again.
 283         * This is only needed when resuming from system sleep.
 284         */
 285        if (!spcm->hw_params_upon_resume[substream->stream])
 286                return 0;
 287
 288        dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id,
 289                substream->stream);
 290
 291        /* set hw_params */
 292        ret = sof_pcm_hw_params(substream, &spcm->params[substream->stream]);
 293        if (ret < 0) {
 294                dev_err(sdev->dev, "error: set pcm hw_params after resume\n");
 295                return ret;
 296        }
 297
 298        return 0;
 299}
 300
 301/*
 302 * FE dai link trigger actions are always executed in non-atomic context because
 303 * they involve IPC's.
 304 */
 305static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 306{
 307        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 308        struct snd_soc_component *component =
 309                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 310        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 311        struct snd_sof_pcm *spcm;
 312        struct sof_ipc_stream stream;
 313        struct sof_ipc_reply reply;
 314        int ret;
 315
 316        /* nothing to do for BE */
 317        if (rtd->dai_link->no_pcm)
 318                return 0;
 319
 320        spcm = snd_sof_find_spcm_dai(sdev, rtd);
 321        if (!spcm)
 322                return -EINVAL;
 323
 324        dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n",
 325                spcm->pcm.pcm_id, substream->stream, cmd);
 326
 327        stream.hdr.size = sizeof(stream);
 328        stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG;
 329        stream.comp_id = spcm->stream[substream->stream].comp_id;
 330
 331        switch (cmd) {
 332        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 333                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
 334                break;
 335        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 336                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
 337                break;
 338        case SNDRV_PCM_TRIGGER_RESUME:
 339                /* set up hw_params */
 340                ret = sof_pcm_prepare(substream);
 341                if (ret < 0) {
 342                        dev_err(sdev->dev,
 343                                "error: failed to set up hw_params upon resume\n");
 344                        return ret;
 345                }
 346
 347                /* fallthrough */
 348        case SNDRV_PCM_TRIGGER_START:
 349                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START;
 350                break;
 351        case SNDRV_PCM_TRIGGER_SUSPEND:
 352        case SNDRV_PCM_TRIGGER_STOP:
 353                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
 354                break;
 355        default:
 356                dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd);
 357                return -EINVAL;
 358        }
 359
 360        snd_sof_pcm_platform_trigger(sdev, substream, cmd);
 361
 362        /* send IPC to the DSP */
 363        ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
 364                                 sizeof(stream), &reply, sizeof(reply));
 365
 366        if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND)
 367                return ret;
 368
 369        /*
 370         * The hw_free op is usually called when the pcm stream is closed.
 371         * Since the stream is not closed during suspend, the DSP needs to be
 372         * notified explicitly to free pcm to prevent errors upon resume.
 373         */
 374        stream.hdr.size = sizeof(stream);
 375        stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
 376        stream.comp_id = spcm->stream[substream->stream].comp_id;
 377
 378        /* send IPC to the DSP */
 379        return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
 380                                  sizeof(stream), &reply, sizeof(reply));
 381}
 382
 383static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream)
 384{
 385        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 386        struct snd_soc_component *component =
 387                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 388        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 389        struct snd_sof_pcm *spcm;
 390        snd_pcm_uframes_t host, dai;
 391
 392        /* nothing to do for BE */
 393        if (rtd->dai_link->no_pcm)
 394                return 0;
 395
 396        /* use dsp ops pointer callback directly if set */
 397        if (sof_ops(sdev)->pcm_pointer)
 398                return sof_ops(sdev)->pcm_pointer(sdev, substream);
 399
 400        spcm = snd_sof_find_spcm_dai(sdev, rtd);
 401        if (!spcm)
 402                return -EINVAL;
 403
 404        /* read position from DSP */
 405        host = bytes_to_frames(substream->runtime,
 406                               spcm->stream[substream->stream].posn.host_posn);
 407        dai = bytes_to_frames(substream->runtime,
 408                              spcm->stream[substream->stream].posn.dai_posn);
 409
 410        dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n",
 411                spcm->pcm.pcm_id, substream->stream, host, dai);
 412
 413        return host;
 414}
 415
 416static int sof_pcm_open(struct snd_pcm_substream *substream)
 417{
 418        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 419        struct snd_pcm_runtime *runtime = substream->runtime;
 420        struct snd_soc_component *component =
 421                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 422        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 423        struct snd_sof_pcm *spcm;
 424        struct snd_soc_tplg_stream_caps *caps;
 425        int ret;
 426
 427        /* nothing to do for BE */
 428        if (rtd->dai_link->no_pcm)
 429                return 0;
 430
 431        spcm = snd_sof_find_spcm_dai(sdev, rtd);
 432        if (!spcm)
 433                return -EINVAL;
 434
 435        dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
 436                substream->stream);
 437
 438        INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
 439                  sof_pcm_period_elapsed_work);
 440
 441        caps = &spcm->pcm.caps[substream->stream];
 442
 443        /* set any runtime constraints based on topology */
 444        snd_pcm_hw_constraint_step(substream->runtime, 0,
 445                                   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 446                                   le32_to_cpu(caps->period_size_min));
 447        snd_pcm_hw_constraint_step(substream->runtime, 0,
 448                                   SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 449                                   le32_to_cpu(caps->period_size_min));
 450
 451        /* set runtime config */
 452        runtime->hw.info = SNDRV_PCM_INFO_MMAP |
 453                          SNDRV_PCM_INFO_MMAP_VALID |
 454                          SNDRV_PCM_INFO_INTERLEAVED |
 455                          SNDRV_PCM_INFO_PAUSE |
 456                          SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
 457        runtime->hw.formats = le64_to_cpu(caps->formats);
 458        runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min);
 459        runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max);
 460        runtime->hw.periods_min = le32_to_cpu(caps->periods_min);
 461        runtime->hw.periods_max = le32_to_cpu(caps->periods_max);
 462
 463        /*
 464         * caps->buffer_size_min is not used since the
 465         * snd_pcm_hardware structure only defines buffer_bytes_max
 466         */
 467        runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
 468
 469        dev_dbg(sdev->dev, "period min %zd max %zd bytes\n",
 470                runtime->hw.period_bytes_min,
 471                runtime->hw.period_bytes_max);
 472        dev_dbg(sdev->dev, "period count %d max %d\n",
 473                runtime->hw.periods_min,
 474                runtime->hw.periods_max);
 475        dev_dbg(sdev->dev, "buffer max %zd bytes\n",
 476                runtime->hw.buffer_bytes_max);
 477
 478        /* set wait time - TODO: come from topology */
 479        substream->wait_time = 500;
 480
 481        spcm->stream[substream->stream].posn.host_posn = 0;
 482        spcm->stream[substream->stream].posn.dai_posn = 0;
 483        spcm->stream[substream->stream].substream = substream;
 484
 485        ret = snd_sof_pcm_platform_open(sdev, substream);
 486        if (ret < 0)
 487                dev_err(sdev->dev, "error: pcm open failed %d\n", ret);
 488
 489        return ret;
 490}
 491
 492static int sof_pcm_close(struct snd_pcm_substream *substream)
 493{
 494        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 495        struct snd_soc_component *component =
 496                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 497        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 498        struct snd_sof_pcm *spcm;
 499        int err;
 500
 501        /* nothing to do for BE */
 502        if (rtd->dai_link->no_pcm)
 503                return 0;
 504
 505        spcm = snd_sof_find_spcm_dai(sdev, rtd);
 506        if (!spcm)
 507                return -EINVAL;
 508
 509        dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id,
 510                substream->stream);
 511
 512        err = snd_sof_pcm_platform_close(sdev, substream);
 513        if (err < 0) {
 514                dev_err(sdev->dev, "error: pcm close failed %d\n",
 515                        err);
 516                /*
 517                 * keep going, no point in preventing the close
 518                 * from happening
 519                 */
 520        }
 521
 522        return 0;
 523}
 524
 525static struct snd_pcm_ops sof_pcm_ops = {
 526        .open           = sof_pcm_open,
 527        .close          = sof_pcm_close,
 528        .ioctl          = snd_pcm_lib_ioctl,
 529        .hw_params      = sof_pcm_hw_params,
 530        .prepare        = sof_pcm_prepare,
 531        .hw_free        = sof_pcm_hw_free,
 532        .trigger        = sof_pcm_trigger,
 533        .pointer        = sof_pcm_pointer,
 534        .page           = snd_pcm_sgbuf_ops_page,
 535};
 536
 537/*
 538 * Pre-allocate playback/capture audio buffer pages.
 539 * no need to explicitly release memory preallocated by sof_pcm_new in pcm_free
 540 * snd_pcm_lib_preallocate_free_for_all() is called by the core.
 541 */
 542static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd)
 543{
 544        struct snd_soc_component *component =
 545                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 546        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 547        struct snd_sof_pcm *spcm;
 548        struct snd_pcm *pcm = rtd->pcm;
 549        struct snd_soc_tplg_stream_caps *caps;
 550        int stream = SNDRV_PCM_STREAM_PLAYBACK;
 551
 552        /* find SOF PCM for this RTD */
 553        spcm = snd_sof_find_spcm_dai(sdev, rtd);
 554        if (!spcm) {
 555                dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
 556                         rtd->dai_link->id);
 557                return 0;
 558        }
 559
 560        dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
 561
 562        /* do we need to pre-allocate playback audio buffer pages */
 563        if (!spcm->pcm.playback)
 564                goto capture;
 565
 566        caps = &spcm->pcm.caps[stream];
 567
 568        /* pre-allocate playback audio buffer pages */
 569        dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
 570                caps->name, caps->buffer_size_min, caps->buffer_size_max);
 571
 572        snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
 573                                      SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
 574                                      le32_to_cpu(caps->buffer_size_min),
 575                                      le32_to_cpu(caps->buffer_size_max));
 576capture:
 577        stream = SNDRV_PCM_STREAM_CAPTURE;
 578
 579        /* do we need to pre-allocate capture audio buffer pages */
 580        if (!spcm->pcm.capture)
 581                return 0;
 582
 583        caps = &spcm->pcm.caps[stream];
 584
 585        /* pre-allocate capture audio buffer pages */
 586        dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
 587                caps->name, caps->buffer_size_min, caps->buffer_size_max);
 588
 589        snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
 590                                      SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
 591                                      le32_to_cpu(caps->buffer_size_min),
 592                                      le32_to_cpu(caps->buffer_size_max));
 593
 594        return 0;
 595}
 596
 597/* fixup the BE DAI link to match any values from topology */
 598static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
 599                                  struct snd_pcm_hw_params *params)
 600{
 601        struct snd_interval *rate = hw_param_interval(params,
 602                        SNDRV_PCM_HW_PARAM_RATE);
 603        struct snd_interval *channels = hw_param_interval(params,
 604                                                SNDRV_PCM_HW_PARAM_CHANNELS);
 605        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 606        struct snd_soc_component *component =
 607                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 608        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 609        struct snd_sof_dai *dai =
 610                snd_sof_find_dai(sdev, (char *)rtd->dai_link->name);
 611
 612        /* no topology exists for this BE, try a common configuration */
 613        if (!dai) {
 614                dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n",
 615                         rtd->dai_link->name);
 616
 617                /*  set 48k, stereo, 16bits by default */
 618                rate->min = 48000;
 619                rate->max = 48000;
 620
 621                channels->min = 2;
 622                channels->max = 2;
 623
 624                snd_mask_none(fmt);
 625                snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 626
 627                return 0;
 628        }
 629
 630        /* read format from topology */
 631        snd_mask_none(fmt);
 632
 633        switch (dai->comp_dai.config.frame_fmt) {
 634        case SOF_IPC_FRAME_S16_LE:
 635                snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 636                break;
 637        case SOF_IPC_FRAME_S24_4LE:
 638                snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
 639                break;
 640        case SOF_IPC_FRAME_S32_LE:
 641                snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
 642                break;
 643        default:
 644                dev_err(sdev->dev, "error: No available DAI format!\n");
 645                return -EINVAL;
 646        }
 647
 648        /* read rate and channels from topology */
 649        switch (dai->dai_config->type) {
 650        case SOF_DAI_INTEL_SSP:
 651                rate->min = dai->dai_config->ssp.fsync_rate;
 652                rate->max = dai->dai_config->ssp.fsync_rate;
 653                channels->min = dai->dai_config->ssp.tdm_slots;
 654                channels->max = dai->dai_config->ssp.tdm_slots;
 655
 656                dev_dbg(sdev->dev,
 657                        "rate_min: %d rate_max: %d\n", rate->min, rate->max);
 658                dev_dbg(sdev->dev,
 659                        "channels_min: %d channels_max: %d\n",
 660                        channels->min, channels->max);
 661
 662                break;
 663        case SOF_DAI_INTEL_DMIC:
 664                /* DMIC only supports 16 or 32 bit formats */
 665                if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
 666                        dev_err(sdev->dev,
 667                                "error: invalid fmt %d for DAI type %d\n",
 668                                dai->comp_dai.config.frame_fmt,
 669                                dai->dai_config->type);
 670                }
 671                break;
 672        case SOF_DAI_INTEL_HDA:
 673                /* do nothing for HDA dai_link */
 674                break;
 675        default:
 676                dev_err(sdev->dev, "error: invalid DAI type %d\n",
 677                        dai->dai_config->type);
 678                break;
 679        }
 680
 681        return 0;
 682}
 683
 684static int sof_pcm_probe(struct snd_soc_component *component)
 685{
 686        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 687        struct snd_sof_pdata *plat_data = sdev->pdata;
 688        const char *tplg_filename;
 689        int ret;
 690
 691        /* load the default topology */
 692        sdev->component = component;
 693
 694        tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
 695                                       "%s/%s",
 696                                       plat_data->tplg_filename_prefix,
 697                                       plat_data->tplg_filename);
 698        if (!tplg_filename)
 699                return -ENOMEM;
 700
 701        ret = snd_sof_load_topology(sdev, tplg_filename);
 702        if (ret < 0) {
 703                dev_err(sdev->dev, "error: failed to load DSP topology %d\n",
 704                        ret);
 705                return ret;
 706        }
 707
 708        /*
 709         * Some platforms in SOF, ex: BYT, may not have their platform PM
 710         * callbacks set. Increment the usage count so as to
 711         * prevent the device from entering runtime suspend.
 712         */
 713        if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
 714                pm_runtime_get_noresume(sdev->dev);
 715
 716        return ret;
 717}
 718
 719static void sof_pcm_remove(struct snd_soc_component *component)
 720{
 721        /* remove topology */
 722        snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
 723}
 724
 725void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
 726{
 727        struct snd_soc_component_driver *pd = &sdev->plat_drv;
 728        struct snd_sof_pdata *plat_data = sdev->pdata;
 729        const char *drv_name;
 730
 731        drv_name = plat_data->machine->drv_name;
 732
 733        pd->name = "sof-audio-component";
 734        pd->probe = sof_pcm_probe;
 735        pd->remove = sof_pcm_remove;
 736        pd->ops = &sof_pcm_ops;
 737#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
 738        pd->compr_ops = &sof_compressed_ops;
 739#endif
 740        pd->pcm_new = sof_pcm_new;
 741        pd->ignore_machine = drv_name;
 742        pd->be_hw_params_fixup = sof_pcm_dai_link_fixup;
 743        pd->be_pcm_base = SOF_BE_PCM_BASE;
 744        pd->use_dai_pcm_id = true;
 745        pd->topology_name_prefix = "sof";
 746
 747         /* increment module refcount when a pcm is opened */
 748        pd->module_get_upon_open = 1;
 749}
 750