linux/sound/soc/uniphier/aio-compress.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Socionext UniPhier AIO Compress Audio driver.
   4//
   5// Copyright (c) 2017-2018 Socionext Inc.
   6
   7#include <linux/bitfield.h>
   8#include <linux/circ_buf.h>
   9#include <linux/dma-mapping.h>
  10#include <linux/errno.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <sound/core.h>
  14#include <sound/pcm.h>
  15#include <sound/soc.h>
  16
  17#include "aio.h"
  18
  19static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream);
  20static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream);
  21
  22static int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd)
  23{
  24        struct snd_compr *compr = rtd->compr;
  25        struct device *dev = compr->card->dev;
  26        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
  27        struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
  28        size_t size = AUD_RING_SIZE;
  29        int dma_dir = DMA_FROM_DEVICE, ret;
  30
  31        ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
  32        if (ret)
  33                return ret;
  34
  35        sub->compr_area = kzalloc(size, GFP_KERNEL);
  36        if (!sub->compr_area)
  37                return -ENOMEM;
  38
  39        if (sub->swm->dir == PORT_DIR_OUTPUT)
  40                dma_dir = DMA_TO_DEVICE;
  41
  42        sub->compr_addr = dma_map_single(dev, sub->compr_area, size, dma_dir);
  43        if (dma_mapping_error(dev, sub->compr_addr)) {
  44                kfree(sub->compr_area);
  45                sub->compr_area = NULL;
  46
  47                return -ENOMEM;
  48        }
  49
  50        sub->compr_bytes = size;
  51
  52        return 0;
  53}
  54
  55static int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd)
  56{
  57        struct snd_compr *compr = rtd->compr;
  58        struct device *dev = compr->card->dev;
  59        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
  60        struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
  61        int dma_dir = DMA_FROM_DEVICE;
  62
  63        if (sub->swm->dir == PORT_DIR_OUTPUT)
  64                dma_dir = DMA_TO_DEVICE;
  65
  66        dma_unmap_single(dev, sub->compr_addr, sub->compr_bytes, dma_dir);
  67        kfree(sub->compr_area);
  68        sub->compr_area = NULL;
  69
  70        return 0;
  71}
  72
  73static int uniphier_aio_compr_open(struct snd_compr_stream *cstream)
  74{
  75        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
  76        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
  77        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
  78        int ret;
  79
  80        if (sub->cstream)
  81                return -EBUSY;
  82
  83        sub->cstream = cstream;
  84        sub->pass_through = 1;
  85        sub->use_mmap = false;
  86
  87        ret = uniphier_aio_comprdma_new(rtd);
  88        if (ret)
  89                return ret;
  90
  91        ret = aio_init(sub);
  92        if (ret)
  93                return ret;
  94
  95        return 0;
  96}
  97
  98static int uniphier_aio_compr_free(struct snd_compr_stream *cstream)
  99{
 100        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 101        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 102        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 103        int ret;
 104
 105        ret = uniphier_aio_compr_hw_free(cstream);
 106        if (ret)
 107                return ret;
 108        ret = uniphier_aio_comprdma_free(rtd);
 109        if (ret)
 110                return ret;
 111
 112        sub->cstream = NULL;
 113
 114        return 0;
 115}
 116
 117static int uniphier_aio_compr_get_params(struct snd_compr_stream *cstream,
 118                                         struct snd_codec *params)
 119{
 120        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 121        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 122        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 123
 124        *params = sub->cparams.codec;
 125
 126        return 0;
 127}
 128
 129static int uniphier_aio_compr_set_params(struct snd_compr_stream *cstream,
 130                                         struct snd_compr_params *params)
 131{
 132        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 133        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 134        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 135        struct device *dev = &aio->chip->pdev->dev;
 136        int ret;
 137
 138        if (params->codec.id != SND_AUDIOCODEC_IEC61937) {
 139                dev_err(dev, "Codec ID is not supported(%d)\n",
 140                        params->codec.id);
 141                return -EINVAL;
 142        }
 143        if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) {
 144                dev_err(dev, "Codec profile is not supported(%d)\n",
 145                        params->codec.profile);
 146                return -EINVAL;
 147        }
 148
 149        /* IEC frame type will be changed after received valid data */
 150        sub->iec_pc = IEC61937_PC_AAC;
 151
 152        sub->cparams = *params;
 153        sub->setting = 1;
 154
 155        aio_port_reset(sub);
 156        aio_src_reset(sub);
 157
 158        ret = uniphier_aio_compr_prepare(cstream);
 159        if (ret)
 160                return ret;
 161
 162        return 0;
 163}
 164
 165static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream)
 166{
 167        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 168        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 169        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 170
 171        sub->setting = 0;
 172
 173        return 0;
 174}
 175
 176static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream)
 177{
 178        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 179        struct snd_compr_runtime *runtime = cstream->runtime;
 180        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 181        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 182        int bytes = runtime->fragment_size;
 183        unsigned long flags;
 184        int ret;
 185
 186        ret = aiodma_ch_set_param(sub);
 187        if (ret)
 188                return ret;
 189
 190        spin_lock_irqsave(&sub->lock, flags);
 191        ret = aiodma_rb_set_buffer(sub, sub->compr_addr,
 192                                   sub->compr_addr + sub->compr_bytes,
 193                                   bytes);
 194        spin_unlock_irqrestore(&sub->lock, flags);
 195        if (ret)
 196                return ret;
 197
 198        ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
 199        if (ret)
 200                return ret;
 201        ret = aio_oport_set_stream_type(sub, sub->iec_pc);
 202        if (ret)
 203                return ret;
 204        aio_port_set_enable(sub, 1);
 205
 206        ret = aio_if_set_param(sub, sub->pass_through);
 207        if (ret)
 208                return ret;
 209
 210        return 0;
 211}
 212
 213static int uniphier_aio_compr_trigger(struct snd_compr_stream *cstream,
 214                                      int cmd)
 215{
 216        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 217        struct snd_compr_runtime *runtime = cstream->runtime;
 218        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 219        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 220        struct device *dev = &aio->chip->pdev->dev;
 221        int bytes = runtime->fragment_size, ret = 0;
 222        unsigned long flags;
 223
 224        spin_lock_irqsave(&sub->lock, flags);
 225        switch (cmd) {
 226        case SNDRV_PCM_TRIGGER_START:
 227                aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
 228                aiodma_ch_set_enable(sub, 1);
 229                sub->running = 1;
 230
 231                break;
 232        case SNDRV_PCM_TRIGGER_STOP:
 233                sub->running = 0;
 234                aiodma_ch_set_enable(sub, 0);
 235
 236                break;
 237        default:
 238                dev_warn(dev, "Unknown trigger(%d)\n", cmd);
 239                ret = -EINVAL;
 240        }
 241        spin_unlock_irqrestore(&sub->lock, flags);
 242
 243        return ret;
 244}
 245
 246static int uniphier_aio_compr_pointer(struct snd_compr_stream *cstream,
 247                                      struct snd_compr_tstamp *tstamp)
 248{
 249        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 250        struct snd_compr_runtime *runtime = cstream->runtime;
 251        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 252        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 253        int bytes = runtime->fragment_size;
 254        unsigned long flags;
 255        u32 pos;
 256
 257        spin_lock_irqsave(&sub->lock, flags);
 258
 259        aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
 260
 261        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 262                pos = sub->rd_offs;
 263                /* Size of AIO output format is double of IEC61937 */
 264                tstamp->copied_total = sub->rd_total / 2;
 265        } else {
 266                pos = sub->wr_offs;
 267                tstamp->copied_total = sub->rd_total;
 268        }
 269        tstamp->byte_offset = pos;
 270
 271        spin_unlock_irqrestore(&sub->lock, flags);
 272
 273        return 0;
 274}
 275
 276static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
 277                                char __user *buf, size_t dstsize)
 278{
 279        u32 __user *srcbuf = (u32 __user *)buf;
 280        u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs);
 281        int src = 0, dst = 0, ret;
 282        u32 frm, frm_a, frm_b;
 283
 284        while (dstsize > 0) {
 285                ret = get_user(frm, srcbuf + src);
 286                if (ret)
 287                        return ret;
 288                src++;
 289
 290                frm_a = frm & 0xffff;
 291                frm_b = (frm >> 16) & 0xffff;
 292
 293                if (frm == IEC61937_HEADER_SIGN) {
 294                        frm_a |= 0x01000000;
 295
 296                        /* Next data is Pc and Pd */
 297                        sub->iec_header = true;
 298                } else {
 299                        u16 pc = be16_to_cpu((__be16)frm_a);
 300
 301                        if (sub->iec_header && sub->iec_pc != pc) {
 302                                /* Force overwrite IEC frame type */
 303                                sub->iec_pc = pc;
 304                                ret = aio_oport_set_stream_type(sub, pc);
 305                                if (ret)
 306                                        return ret;
 307                        }
 308                        sub->iec_header = false;
 309                }
 310                dstbuf[dst++] = frm_a;
 311                dstbuf[dst++] = frm_b;
 312
 313                dstsize -= sizeof(u32) * 2;
 314        }
 315
 316        return 0;
 317}
 318
 319static int uniphier_aio_compr_copy(struct snd_compr_stream *cstream,
 320                                   char __user *buf, size_t count)
 321{
 322        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 323        struct snd_compr_runtime *runtime = cstream->runtime;
 324        struct device *carddev = rtd->compr->card->dev;
 325        struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 326        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 327        size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
 328        int bytes = runtime->fragment_size;
 329        unsigned long flags;
 330        size_t s;
 331        int ret;
 332
 333        if (cnt < sizeof(u32))
 334                return 0;
 335
 336        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 337                dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;
 338
 339                /* Size of AIO output format is double of IEC61937 */
 340                s = cnt * 2;
 341
 342                dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
 343                ret = aio_compr_send_to_hw(sub, buf, s);
 344                dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
 345        } else {
 346                dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;
 347
 348                s = cnt;
 349
 350                dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
 351                ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
 352                dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
 353        }
 354        if (ret)
 355                return -EFAULT;
 356
 357        spin_lock_irqsave(&sub->lock, flags);
 358
 359        sub->threshold = 2 * bytes;
 360        aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);
 361
 362        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 363                sub->wr_offs += s;
 364                if (sub->wr_offs >= sub->compr_bytes)
 365                        sub->wr_offs -= sub->compr_bytes;
 366        } else {
 367                sub->rd_offs += s;
 368                if (sub->rd_offs >= sub->compr_bytes)
 369                        sub->rd_offs -= sub->compr_bytes;
 370        }
 371        aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
 372
 373        spin_unlock_irqrestore(&sub->lock, flags);
 374
 375        return cnt;
 376}
 377
 378static int uniphier_aio_compr_get_caps(struct snd_compr_stream *cstream,
 379                                       struct snd_compr_caps *caps)
 380{
 381        caps->num_codecs = 1;
 382        caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
 383        caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;
 384        caps->min_fragments = AUD_MIN_FRAGMENT;
 385        caps->max_fragments = AUD_MAX_FRAGMENT;
 386        caps->codecs[0] = SND_AUDIOCODEC_IEC61937;
 387
 388        return 0;
 389}
 390
 391static const struct snd_compr_codec_caps caps_iec = {
 392        .num_descriptors = 1,
 393        .descriptor[0].max_ch = 8,
 394        .descriptor[0].num_sample_rates = 0,
 395        .descriptor[0].num_bitrates = 0,
 396        .descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF,
 397        .descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 |
 398                                SND_AUDIOMODE_IEC_MPEG1 |
 399                                SND_AUDIOMODE_IEC_MP3 |
 400                                SND_AUDIOMODE_IEC_DTS,
 401        .descriptor[0].formats = 0,
 402};
 403
 404static int uniphier_aio_compr_get_codec_caps(struct snd_compr_stream *stream,
 405                                             struct snd_compr_codec_caps *codec)
 406{
 407        if (codec->codec == SND_AUDIOCODEC_IEC61937)
 408                *codec = caps_iec;
 409        else
 410                return -EINVAL;
 411
 412        return 0;
 413}
 414
 415const struct snd_compr_ops uniphier_aio_compr_ops = {
 416        .open           = uniphier_aio_compr_open,
 417        .free           = uniphier_aio_compr_free,
 418        .get_params     = uniphier_aio_compr_get_params,
 419        .set_params     = uniphier_aio_compr_set_params,
 420        .trigger        = uniphier_aio_compr_trigger,
 421        .pointer        = uniphier_aio_compr_pointer,
 422        .copy           = uniphier_aio_compr_copy,
 423        .get_caps       = uniphier_aio_compr_get_caps,
 424        .get_codec_caps = uniphier_aio_compr_get_codec_caps,
 425};
 426