root/sound/soc/au1x/dbdma2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. au1x_pcm_queue_tx
  2. au1x_pcm_queue_rx
  3. au1x_pcm_dmatx_cb
  4. au1x_pcm_dmarx_cb
  5. au1x_pcm_dbdma_free
  6. au1x_pcm_dbdma_realloc
  7. to_dmadata
  8. au1xpsc_pcm_hw_params
  9. au1xpsc_pcm_hw_free
  10. au1xpsc_pcm_prepare
  11. au1xpsc_pcm_trigger
  12. au1xpsc_pcm_pointer
  13. au1xpsc_pcm_open
  14. au1xpsc_pcm_close
  15. au1xpsc_pcm_new
  16. au1xpsc_pcm_drvprobe

   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 {
 187         struct snd_soc_pcm_runtime *rtd = ss->private_data;
 188         struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 189         struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component);
 190         return &pcd[ss->stream];
 191 }
 192 
 193 static int au1xpsc_pcm_hw_params(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);
 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_pcm_substream *substream)
 236 {
 237         snd_pcm_lib_free_pages(substream);
 238         return 0;
 239 }
 240 
 241 static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
 242 {
 243         struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
 244 
 245         au1xxx_dbdma_reset(pcd->ddma_chan);
 246 
 247         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 248                 au1x_pcm_queue_rx(pcd);
 249                 au1x_pcm_queue_rx(pcd);
 250         } else {
 251                 au1x_pcm_queue_tx(pcd);
 252                 au1x_pcm_queue_tx(pcd);
 253         }
 254 
 255         return 0;
 256 }
 257 
 258 static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 259 {
 260         u32 c = to_dmadata(substream)->ddma_chan;
 261 
 262         switch (cmd) {
 263         case SNDRV_PCM_TRIGGER_START:
 264         case SNDRV_PCM_TRIGGER_RESUME:
 265                 au1xxx_dbdma_start(c);
 266                 break;
 267         case SNDRV_PCM_TRIGGER_STOP:
 268         case SNDRV_PCM_TRIGGER_SUSPEND:
 269                 au1xxx_dbdma_stop(c);
 270                 break;
 271         default:
 272                 return -EINVAL;
 273         }
 274         return 0;
 275 }
 276 
 277 static snd_pcm_uframes_t
 278 au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
 279 {
 280         return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
 281 }
 282 
 283 static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
 284 {
 285         struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
 286         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 287         int stype = substream->stream, *dmaids;
 288 
 289         dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 290         if (!dmaids)
 291                 return -ENODEV; /* whoa, has ordering changed? */
 292 
 293         pcd->ddma_id = dmaids[stype];
 294 
 295         snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
 296         return 0;
 297 }
 298 
 299 static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
 300 {
 301         au1x_pcm_dbdma_free(to_dmadata(substream));
 302         return 0;
 303 }
 304 
 305 static const struct snd_pcm_ops au1xpsc_pcm_ops = {
 306         .open           = au1xpsc_pcm_open,
 307         .close          = au1xpsc_pcm_close,
 308         .ioctl          = snd_pcm_lib_ioctl,
 309         .hw_params      = au1xpsc_pcm_hw_params,
 310         .hw_free        = au1xpsc_pcm_hw_free,
 311         .prepare        = au1xpsc_pcm_prepare,
 312         .trigger        = au1xpsc_pcm_trigger,
 313         .pointer        = au1xpsc_pcm_pointer,
 314 };
 315 
 316 static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 317 {
 318         struct snd_card *card = rtd->card->snd_card;
 319         struct snd_pcm *pcm = rtd->pcm;
 320 
 321         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 322                 card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
 323 
 324         return 0;
 325 }
 326 
 327 /* au1xpsc audio platform */
 328 static struct snd_soc_component_driver au1xpsc_soc_component = {
 329         .name           = DRV_NAME,
 330         .ops            = &au1xpsc_pcm_ops,
 331         .pcm_new        = au1xpsc_pcm_new,
 332 };
 333 
 334 static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
 335 {
 336         struct au1xpsc_audio_dmadata *dmadata;
 337 
 338         dmadata = devm_kcalloc(&pdev->dev,
 339                                2, sizeof(struct au1xpsc_audio_dmadata),
 340                                GFP_KERNEL);
 341         if (!dmadata)
 342                 return -ENOMEM;
 343 
 344         platform_set_drvdata(pdev, dmadata);
 345 
 346         return devm_snd_soc_register_component(&pdev->dev,
 347                                         &au1xpsc_soc_component, NULL, 0);
 348 }
 349 
 350 static struct platform_driver au1xpsc_pcm_driver = {
 351         .driver = {
 352                 .name   = "au1xpsc-pcm",
 353         },
 354         .probe          = au1xpsc_pcm_drvprobe,
 355 };
 356 
 357 module_platform_driver(au1xpsc_pcm_driver);
 358 
 359 MODULE_LICENSE("GPL");
 360 MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
 361 MODULE_AUTHOR("Manuel Lauss");

/* [<][>][^][v][top][bottom][index][help] */