~hui.wang/alsa-driver/dkms-packaging.audiosdw-ppa

« back to all changes in this revision

Viewing changes to buildroot/src/oem-audiosdw-lp1836324-0.6ubuntu1.2/soc/sof/pcm.c

  • Committer: Hui Wang
  • Date: 2019-12-13 02:41:40 UTC
  • Revision ID: hui.wang@canonical.com-20191213024140-1cprdcbl3122fn85
insert pc-oem-dkms

Show diffs side-by-side

added added

removed removed

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