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