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