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