~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/au1x/dbdma2.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-only
2
 
/*
3
 
 * Au12x0/Au1550 PSC ALSA ASoC audio support.
4
 
 *
5
 
 * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
6
 
 *      Manuel Lauss <manuel.lauss@gmail.com>
7
 
 *
8
 
 * DMA glue for Au1x-PSC audio.
9
 
 */
10
 
 
11
 
 
12
 
#include <linux/module.h>
13
 
#include <linux/init.h>
14
 
#include <linux/platform_device.h>
15
 
#include <linux/slab.h>
16
 
#include <linux/dma-mapping.h>
17
 
 
18
 
#include <sound/core.h>
19
 
#include <sound/pcm.h>
20
 
#include <sound/pcm_params.h>
21
 
#include <sound/soc.h>
22
 
 
23
 
#include <asm/mach-au1x00/au1000.h>
24
 
#include <asm/mach-au1x00/au1xxx_dbdma.h>
25
 
#include <asm/mach-au1x00/au1xxx_psc.h>
26
 
 
27
 
#include "psc.h"
28
 
 
29
 
/*#define PCM_DEBUG*/
30
 
 
31
 
#define DRV_NAME "dbdma2"
32
 
 
33
 
#define MSG(x...)       printk(KERN_INFO "au1xpsc_pcm: " x)
34
 
#ifdef PCM_DEBUG
35
 
#define DBG             MSG
36
 
#else
37
 
#define DBG(x...)       do {} while (0)
38
 
#endif
39
 
 
40
 
struct au1xpsc_audio_dmadata {
41
 
        /* DDMA control data */
42
 
        unsigned int ddma_id;           /* DDMA direction ID for this PSC */
43
 
        u32 ddma_chan;                  /* DDMA context */
44
 
 
45
 
        /* PCM context (for irq handlers) */
46
 
        struct snd_pcm_substream *substream;
47
 
        unsigned long curr_period;      /* current segment DDMA is working on */
48
 
        unsigned long q_period;         /* queue period(s) */
49
 
        dma_addr_t dma_area;            /* address of queued DMA area */
50
 
        dma_addr_t dma_area_s;          /* start address of DMA area */
51
 
        unsigned long pos;              /* current byte position being played */
52
 
        unsigned long periods;          /* number of SG segments in total */
53
 
        unsigned long period_bytes;     /* size in bytes of one SG segment */
54
 
 
55
 
        /* runtime data */
56
 
        int msbits;
57
 
};
58
 
 
59
 
/*
60
 
 * These settings are somewhat okay, at least on my machine audio plays
61
 
 * almost skip-free. Especially the 64kB buffer seems to help a LOT.
62
 
 */
63
 
#define AU1XPSC_PERIOD_MIN_BYTES        1024
64
 
#define AU1XPSC_BUFFER_MIN_BYTES        65536
65
 
 
66
 
/* PCM hardware DMA capabilities - platform specific */
67
 
static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
68
 
        .info             = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
69
 
                            SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
70
 
        .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES,
71
 
        .period_bytes_max = 4096 * 1024 - 1,
72
 
        .periods_min      = 2,
73
 
        .periods_max      = 4096,       /* 2 to as-much-as-you-like */
74
 
        .buffer_bytes_max = 4096 * 1024 - 1,
75
 
        .fifo_size        = 16,         /* fifo entries of AC97/I2S PSC */
76
 
};
77
 
 
78
 
static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd)
79
 
{
80
 
        au1xxx_dbdma_put_source(cd->ddma_chan, cd->dma_area,
81
 
                                cd->period_bytes, DDMA_FLAGS_IE);
82
 
 
83
 
        /* update next-to-queue period */
84
 
        ++cd->q_period;
85
 
        cd->dma_area += cd->period_bytes;
86
 
        if (cd->q_period >= cd->periods) {
87
 
                cd->q_period = 0;
88
 
                cd->dma_area = cd->dma_area_s;
89
 
        }
90
 
}
91
 
 
92
 
static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd)
93
 
{
94
 
        au1xxx_dbdma_put_dest(cd->ddma_chan, cd->dma_area,
95
 
                              cd->period_bytes, DDMA_FLAGS_IE);
96
 
 
97
 
        /* update next-to-queue period */
98
 
        ++cd->q_period;
99
 
        cd->dma_area += cd->period_bytes;
100
 
        if (cd->q_period >= cd->periods) {
101
 
                cd->q_period = 0;
102
 
                cd->dma_area = cd->dma_area_s;
103
 
        }
104
 
}
105
 
 
106
 
static void au1x_pcm_dmatx_cb(int irq, void *dev_id)
107
 
{
108
 
        struct au1xpsc_audio_dmadata *cd = dev_id;
109
 
 
110
 
        cd->pos += cd->period_bytes;
111
 
        if (++cd->curr_period >= cd->periods) {
112
 
                cd->pos = 0;
113
 
                cd->curr_period = 0;
114
 
        }
115
 
        snd_pcm_period_elapsed(cd->substream);
116
 
        au1x_pcm_queue_tx(cd);
117
 
}
118
 
 
119
 
static void au1x_pcm_dmarx_cb(int irq, void *dev_id)
120
 
{
121
 
        struct au1xpsc_audio_dmadata *cd = dev_id;
122
 
 
123
 
        cd->pos += cd->period_bytes;
124
 
        if (++cd->curr_period >= cd->periods) {
125
 
                cd->pos = 0;
126
 
                cd->curr_period = 0;
127
 
        }
128
 
        snd_pcm_period_elapsed(cd->substream);
129
 
        au1x_pcm_queue_rx(cd);
130
 
}
131
 
 
132
 
static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd)
133
 
{
134
 
        if (pcd->ddma_chan) {
135
 
                au1xxx_dbdma_stop(pcd->ddma_chan);
136
 
                au1xxx_dbdma_reset(pcd->ddma_chan);
137
 
                au1xxx_dbdma_chan_free(pcd->ddma_chan);
138
 
                pcd->ddma_chan = 0;
139
 
                pcd->msbits = 0;
140
 
        }
141
 
}
142
 
 
143
 
/* in case of missing DMA ring or changed TX-source / RX-dest bit widths,
144
 
 * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according
145
 
 * to ALSA-supplied sample depth.  This is due to limitations in the dbdma api
146
 
 * (cannot adjust source/dest widths of already allocated descriptor ring).
147
 
 */
148
 
static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
149
 
                                 int stype, int msbits)
150
 
{
151
 
        /* DMA only in 8/16/32 bit widths */
152
 
        if (msbits == 24)
153
 
                msbits = 32;
154
 
 
155
 
        /* check current config: correct bits and descriptors allocated? */
156
 
        if ((pcd->ddma_chan) && (msbits == pcd->msbits))
157
 
                goto out;       /* all ok! */
158
 
 
159
 
        au1x_pcm_dbdma_free(pcd);
160
 
 
161
 
        if (stype == SNDRV_PCM_STREAM_CAPTURE)
162
 
                pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id,
163
 
                                        DSCR_CMD0_ALWAYS,
164
 
                                        au1x_pcm_dmarx_cb, (void *)pcd);
165
 
        else
166
 
                pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
167
 
                                        pcd->ddma_id,
168
 
                                        au1x_pcm_dmatx_cb, (void *)pcd);
169
 
 
170
 
        if (!pcd->ddma_chan)
171
 
                return -ENOMEM;
172
 
 
173
 
        au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits);
174
 
        au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2);
175
 
 
176
 
        pcd->msbits = msbits;
177
 
 
178
 
        au1xxx_dbdma_stop(pcd->ddma_chan);
179
 
        au1xxx_dbdma_reset(pcd->ddma_chan);
180
 
 
181
 
out:
182
 
        return 0;
183
 
}
184
 
 
185
 
static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss,
186
 
                                                       struct snd_soc_component *component)
187
 
{
188
 
        struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component);
189
 
        return &pcd[ss->stream];
190
 
}
191
 
 
192
 
static int au1xpsc_pcm_hw_params(struct snd_soc_component *component,
193
 
                                 struct snd_pcm_substream *substream,
194
 
                                 struct snd_pcm_hw_params *params)
195
 
{
196
 
        struct snd_pcm_runtime *runtime = substream->runtime;
197
 
        struct au1xpsc_audio_dmadata *pcd;
198
 
        int stype, ret;
199
 
 
200
 
        ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
201
 
        if (ret < 0)
202
 
                goto out;
203
 
 
204
 
        stype = substream->stream;
205
 
        pcd = to_dmadata(substream, component);
206
 
 
207
 
        DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu "
208
 
            "runtime->min_align %lu\n",
209
 
                (unsigned long)runtime->dma_area,
210
 
                (unsigned long)runtime->dma_addr, runtime->dma_bytes,
211
 
                runtime->min_align);
212
 
 
213
 
        DBG("bits %d  frags %d  frag_bytes %d  is_rx %d\n", params->msbits,
214
 
                params_periods(params), params_period_bytes(params), stype);
215
 
 
216
 
        ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits);
217
 
        if (ret) {
218
 
                MSG("DDMA channel (re)alloc failed!\n");
219
 
                goto out;
220
 
        }
221
 
 
222
 
        pcd->substream = substream;
223
 
        pcd->period_bytes = params_period_bytes(params);
224
 
        pcd->periods = params_periods(params);
225
 
        pcd->dma_area_s = pcd->dma_area = runtime->dma_addr;
226
 
        pcd->q_period = 0;
227
 
        pcd->curr_period = 0;
228
 
        pcd->pos = 0;
229
 
 
230
 
        ret = 0;
231
 
out:
232
 
        return ret;
233
 
}
234
 
 
235
 
static int au1xpsc_pcm_hw_free(struct snd_soc_component *component,
236
 
                               struct snd_pcm_substream *substream)
237
 
{
238
 
        snd_pcm_lib_free_pages(substream);
239
 
        return 0;
240
 
}
241
 
 
242
 
static int au1xpsc_pcm_prepare(struct snd_soc_component *component,
243
 
                               struct snd_pcm_substream *substream)
244
 
{
245
 
        struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component);
246
 
 
247
 
        au1xxx_dbdma_reset(pcd->ddma_chan);
248
 
 
249
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
250
 
                au1x_pcm_queue_rx(pcd);
251
 
                au1x_pcm_queue_rx(pcd);
252
 
        } else {
253
 
                au1x_pcm_queue_tx(pcd);
254
 
                au1x_pcm_queue_tx(pcd);
255
 
        }
256
 
 
257
 
        return 0;
258
 
}
259
 
 
260
 
static int au1xpsc_pcm_trigger(struct snd_soc_component *component,
261
 
                               struct snd_pcm_substream *substream, int cmd)
262
 
{
263
 
        u32 c = to_dmadata(substream, component)->ddma_chan;
264
 
 
265
 
        switch (cmd) {
266
 
        case SNDRV_PCM_TRIGGER_START:
267
 
        case SNDRV_PCM_TRIGGER_RESUME:
268
 
                au1xxx_dbdma_start(c);
269
 
                break;
270
 
        case SNDRV_PCM_TRIGGER_STOP:
271
 
        case SNDRV_PCM_TRIGGER_SUSPEND:
272
 
                au1xxx_dbdma_stop(c);
273
 
                break;
274
 
        default:
275
 
                return -EINVAL;
276
 
        }
277
 
        return 0;
278
 
}
279
 
 
280
 
static snd_pcm_uframes_t
281
 
au1xpsc_pcm_pointer(struct snd_soc_component *component,
282
 
                    struct snd_pcm_substream *substream)
283
 
{
284
 
        return bytes_to_frames(substream->runtime,
285
 
                               to_dmadata(substream, component)->pos);
286
 
}
287
 
 
288
 
static int au1xpsc_pcm_open(struct snd_soc_component *component,
289
 
                            struct snd_pcm_substream *substream)
290
 
{
291
 
        struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component);
292
 
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
293
 
        int stype = substream->stream, *dmaids;
294
 
 
295
 
        dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
296
 
        if (!dmaids)
297
 
                return -ENODEV; /* whoa, has ordering changed? */
298
 
 
299
 
        pcd->ddma_id = dmaids[stype];
300
 
 
301
 
        snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
302
 
        return 0;
303
 
}
304
 
 
305
 
static int au1xpsc_pcm_close(struct snd_soc_component *component,
306
 
                             struct snd_pcm_substream *substream)
307
 
{
308
 
        au1x_pcm_dbdma_free(to_dmadata(substream, component));
309
 
        return 0;
310
 
}
311
 
 
312
 
static int au1xpsc_pcm_new(struct snd_soc_component *component,
313
 
                           struct snd_soc_pcm_runtime *rtd)
314
 
{
315
 
        struct snd_card *card = rtd->card->snd_card;
316
 
        struct snd_pcm *pcm = rtd->pcm;
317
 
 
318
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
319
 
                card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
320
 
 
321
 
        return 0;
322
 
}
323
 
 
324
 
/* au1xpsc audio platform */
325
 
static struct snd_soc_component_driver au1xpsc_soc_component = {
326
 
        .name           = DRV_NAME,
327
 
        .open           = au1xpsc_pcm_open,
328
 
        .close          = au1xpsc_pcm_close,
329
 
        .ioctl          = snd_soc_pcm_lib_ioctl,
330
 
        .hw_params      = au1xpsc_pcm_hw_params,
331
 
        .hw_free        = au1xpsc_pcm_hw_free,
332
 
        .prepare        = au1xpsc_pcm_prepare,
333
 
        .trigger        = au1xpsc_pcm_trigger,
334
 
        .pointer        = au1xpsc_pcm_pointer,
335
 
        .pcm_construct  = au1xpsc_pcm_new,
336
 
};
337
 
 
338
 
static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
339
 
{
340
 
        struct au1xpsc_audio_dmadata *dmadata;
341
 
 
342
 
        dmadata = devm_kcalloc(&pdev->dev,
343
 
                               2, sizeof(struct au1xpsc_audio_dmadata),
344
 
                               GFP_KERNEL);
345
 
        if (!dmadata)
346
 
                return -ENOMEM;
347
 
 
348
 
        platform_set_drvdata(pdev, dmadata);
349
 
 
350
 
        return devm_snd_soc_register_component(&pdev->dev,
351
 
                                        &au1xpsc_soc_component, NULL, 0);
352
 
}
353
 
 
354
 
static struct platform_driver au1xpsc_pcm_driver = {
355
 
        .driver = {
356
 
                .name   = "au1xpsc-pcm",
357
 
        },
358
 
        .probe          = au1xpsc_pcm_drvprobe,
359
 
};
360
 
 
361
 
module_platform_driver(au1xpsc_pcm_driver);
362
 
 
363
 
MODULE_LICENSE("GPL");
364
 
MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
365
 
MODULE_AUTHOR("Manuel Lauss");