linux/sound/soc/intel/atom/sst/sst_stream.c
<<
>>
Prefs
   1/*
   2 *  sst_stream.c - Intel SST Driver for audio engine
   3 *
   4 *  Copyright (C) 2008-14 Intel Corp
   5 *  Authors:    Vinod Koul <vinod.koul@intel.com>
   6 *              Harsha Priya <priya.harsha@intel.com>
   7 *              Dharageswari R <dharageswari.r@intel.com>
   8 *              KP Jeeja <jeeja.kp@intel.com>
   9 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  10 *
  11 *  This program is free software; you can redistribute it and/or modify
  12 *  it under the terms of the GNU General Public License as published by
  13 *  the Free Software Foundation; version 2 of the License.
  14 *
  15 *  This program is distributed in the hope that it will be useful, but
  16 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 *  General Public License for more details.
  19 *
  20 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  21 */
  22#include <linux/pci.h>
  23#include <linux/firmware.h>
  24#include <linux/sched.h>
  25#include <linux/delay.h>
  26#include <linux/pm_runtime.h>
  27#include <sound/core.h>
  28#include <sound/pcm.h>
  29#include <sound/soc.h>
  30#include <sound/compress_driver.h>
  31#include <asm/platform_sst_audio.h>
  32#include "../sst-mfld-platform.h"
  33#include "sst.h"
  34#include "../../common/sst-dsp.h"
  35
  36int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
  37{
  38        struct snd_sst_alloc_mrfld alloc_param;
  39        struct snd_sst_params *str_params;
  40        struct snd_sst_tstamp fw_tstamp;
  41        struct stream_info *str_info;
  42        struct snd_sst_alloc_response *response;
  43        unsigned int str_id, pipe_id, task_id;
  44        int i, num_ch, ret = 0;
  45        void *data = NULL;
  46
  47        dev_dbg(sst_drv_ctx->dev, "Enter\n");
  48        BUG_ON(!params);
  49
  50        str_params = (struct snd_sst_params *)params;
  51        memset(&alloc_param, 0, sizeof(alloc_param));
  52        alloc_param.operation = str_params->ops;
  53        alloc_param.codec_type = str_params->codec;
  54        alloc_param.sg_count = str_params->aparams.sg_count;
  55        alloc_param.ring_buf_info[0].addr =
  56                str_params->aparams.ring_buf_info[0].addr;
  57        alloc_param.ring_buf_info[0].size =
  58                str_params->aparams.ring_buf_info[0].size;
  59        alloc_param.frag_size = str_params->aparams.frag_size;
  60
  61        memcpy(&alloc_param.codec_params, &str_params->sparams,
  62                        sizeof(struct snd_sst_stream_params));
  63
  64        /*
  65         * fill channel map params for multichannel support.
  66         * Ideally channel map should be received from upper layers
  67         * for multichannel support.
  68         * Currently hardcoding as per FW reqm.
  69         */
  70        num_ch = sst_get_num_channel(str_params);
  71        for (i = 0; i < 8; i++) {
  72                if (i < num_ch)
  73                        alloc_param.codec_params.uc.pcm_params.channel_map[i] = i;
  74                else
  75                        alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF;
  76        }
  77
  78        str_id = str_params->stream_id;
  79        str_info = get_stream_info(sst_drv_ctx, str_id);
  80        if (str_info == NULL) {
  81                dev_err(sst_drv_ctx->dev, "get stream info returned null\n");
  82                return -EINVAL;
  83        }
  84
  85        pipe_id = str_params->device_type;
  86        task_id = str_params->task;
  87        sst_drv_ctx->streams[str_id].pipe_id = pipe_id;
  88        sst_drv_ctx->streams[str_id].task_id = task_id;
  89        sst_drv_ctx->streams[str_id].num_ch = num_ch;
  90
  91        if (sst_drv_ctx->info.lpe_viewpt_rqd)
  92                alloc_param.ts = sst_drv_ctx->info.mailbox_start +
  93                        sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
  94        else
  95                alloc_param.ts = sst_drv_ctx->mailbox_add +
  96                        sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
  97
  98        dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
  99                        alloc_param.ts);
 100        dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
 101                        pipe_id, task_id);
 102
 103        /* allocate device type context */
 104        sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type,
 105                        str_id, alloc_param.operation, 0);
 106
 107        dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
 108                        str_id, pipe_id);
 109        ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
 110                        IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
 111                        &alloc_param, &data, true, true, false, true);
 112
 113        if (ret < 0) {
 114                dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
 115                /* alloc failed, so reset the state to uninit */
 116                str_info->status = STREAM_UN_INIT;
 117                str_id = ret;
 118        } else if (data) {
 119                response = (struct snd_sst_alloc_response *)data;
 120                ret = response->str_type.result;
 121                if (!ret)
 122                        goto out;
 123                dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
 124                if (ret == SST_ERR_STREAM_IN_USE) {
 125                        dev_err(sst_drv_ctx->dev,
 126                                "FW not in clean state, send free for:%d\n", str_id);
 127                        sst_free_stream(sst_drv_ctx, str_id);
 128                }
 129                str_id = -ret;
 130        }
 131out:
 132        kfree(data);
 133        return str_id;
 134}
 135
 136/**
 137* sst_start_stream - Send msg for a starting stream
 138* @str_id:       stream ID
 139*
 140* This function is called by any function which wants to start
 141* a stream.
 142*/
 143int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
 144{
 145        int retval = 0;
 146        struct stream_info *str_info;
 147        u16 data = 0;
 148
 149        dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id);
 150        str_info = get_stream_info(sst_drv_ctx, str_id);
 151        if (!str_info)
 152                return -EINVAL;
 153        if (str_info->status != STREAM_RUNNING)
 154                return -EBADRQC;
 155
 156        retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
 157                        IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id,
 158                        sizeof(u16), &data, NULL, true, true, true, false);
 159
 160        return retval;
 161}
 162
 163int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
 164                struct snd_sst_bytes_v2 *bytes)
 165{       struct ipc_post *msg = NULL;
 166        u32 length;
 167        int pvt_id, ret = 0;
 168        struct sst_block *block = NULL;
 169
 170        dev_dbg(sst_drv_ctx->dev,
 171                "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
 172                bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
 173                bytes->pipe_id, bytes->len);
 174
 175        if (sst_create_ipc_msg(&msg, true))
 176                return -ENOMEM;
 177
 178        pvt_id = sst_assign_pvt_id(sst_drv_ctx);
 179        sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
 180                        bytes->task_id, 1, pvt_id);
 181        msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
 182        length = bytes->len;
 183        msg->mrfld_header.p.header_low_payload = length;
 184        dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
 185        memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
 186        if (bytes->block) {
 187                block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
 188                if (block == NULL) {
 189                        kfree(msg);
 190                        ret = -ENOMEM;
 191                        goto out;
 192                }
 193        }
 194
 195        sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
 196        dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
 197                        msg->mrfld_header.p.header_low_payload);
 198
 199        if (bytes->block) {
 200                ret = sst_wait_timeout(sst_drv_ctx, block);
 201                if (ret) {
 202                        dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
 203                        sst_free_block(sst_drv_ctx, block);
 204                        goto out;
 205                }
 206        }
 207        if (bytes->type == SND_SST_BYTES_GET) {
 208                /*
 209                 * copy the reply and send back
 210                 * we need to update only sz and payload
 211                 */
 212                if (bytes->block) {
 213                        unsigned char *r = block->data;
 214
 215                        dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
 216                                        bytes->len);
 217                        memcpy(bytes->bytes, r, bytes->len);
 218                }
 219        }
 220        if (bytes->block)
 221                sst_free_block(sst_drv_ctx, block);
 222out:
 223        test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
 224        return 0;
 225}
 226
 227/*
 228 * sst_pause_stream - Send msg for a pausing stream
 229 * @str_id:      stream ID
 230 *
 231 * This function is called by any function which wants to pause
 232 * an already running stream.
 233 */
 234int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
 235{
 236        int retval = 0;
 237        struct stream_info *str_info;
 238
 239        dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
 240        str_info = get_stream_info(sst_drv_ctx, str_id);
 241        if (!str_info)
 242                return -EINVAL;
 243        if (str_info->status == STREAM_PAUSED)
 244                return 0;
 245        if (str_info->status == STREAM_RUNNING ||
 246                str_info->status == STREAM_INIT) {
 247                if (str_info->prev == STREAM_UN_INIT)
 248                        return -EBADRQC;
 249
 250                retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
 251                                IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
 252                                0, NULL, NULL, true, true, false, true);
 253
 254                if (retval == 0) {
 255                        str_info->prev = str_info->status;
 256                        str_info->status = STREAM_PAUSED;
 257                } else if (retval == SST_ERR_INVALID_STREAM_ID) {
 258                        retval = -EINVAL;
 259                        mutex_lock(&sst_drv_ctx->sst_lock);
 260                        sst_clean_stream(str_info);
 261                        mutex_unlock(&sst_drv_ctx->sst_lock);
 262                }
 263        } else {
 264                retval = -EBADRQC;
 265                dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n ");
 266        }
 267
 268        return retval;
 269}
 270
 271/**
 272 * sst_resume_stream - Send msg for resuming stream
 273 * @str_id:             stream ID
 274 *
 275 * This function is called by any function which wants to resume
 276 * an already paused stream.
 277 */
 278int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
 279{
 280        int retval = 0;
 281        struct stream_info *str_info;
 282
 283        dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
 284        str_info = get_stream_info(sst_drv_ctx, str_id);
 285        if (!str_info)
 286                return -EINVAL;
 287        if (str_info->status == STREAM_RUNNING)
 288                        return 0;
 289        if (str_info->status == STREAM_PAUSED) {
 290                retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
 291                                IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
 292                                str_info->pipe_id, 0, NULL, NULL,
 293                                true, true, false, true);
 294
 295                if (!retval) {
 296                        if (str_info->prev == STREAM_RUNNING)
 297                                str_info->status = STREAM_RUNNING;
 298                        else
 299                                str_info->status = STREAM_INIT;
 300                        str_info->prev = STREAM_PAUSED;
 301                } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
 302                        retval = -EINVAL;
 303                        mutex_lock(&sst_drv_ctx->sst_lock);
 304                        sst_clean_stream(str_info);
 305                        mutex_unlock(&sst_drv_ctx->sst_lock);
 306                }
 307        } else {
 308                retval = -EBADRQC;
 309                dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
 310        }
 311
 312        return retval;
 313}
 314
 315
 316/**
 317 * sst_drop_stream - Send msg for stopping stream
 318 * @str_id:             stream ID
 319 *
 320 * This function is called by any function which wants to stop
 321 * a stream.
 322 */
 323int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
 324{
 325        int retval = 0;
 326        struct stream_info *str_info;
 327
 328        dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
 329        str_info = get_stream_info(sst_drv_ctx, str_id);
 330        if (!str_info)
 331                return -EINVAL;
 332
 333        if (str_info->status != STREAM_UN_INIT) {
 334                str_info->prev = STREAM_UN_INIT;
 335                str_info->status = STREAM_INIT;
 336                str_info->cumm_bytes = 0;
 337                retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
 338                                IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
 339                                str_info->pipe_id, 0, NULL, NULL,
 340                                true, true, true, false);
 341        } else {
 342                retval = -EBADRQC;
 343                dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
 344                                str_info->status);
 345        }
 346        return retval;
 347}
 348
 349/**
 350* sst_drain_stream - Send msg for draining stream
 351* @str_id:              stream ID
 352*
 353* This function is called by any function which wants to drain
 354* a stream.
 355*/
 356int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
 357                        int str_id, bool partial_drain)
 358{
 359        int retval = 0;
 360        struct stream_info *str_info;
 361
 362        dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id);
 363        str_info = get_stream_info(sst_drv_ctx, str_id);
 364        if (!str_info)
 365                return -EINVAL;
 366        if (str_info->status != STREAM_RUNNING &&
 367                str_info->status != STREAM_INIT &&
 368                str_info->status != STREAM_PAUSED) {
 369                        dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
 370                                       str_info->status);
 371                        return -EBADRQC;
 372        }
 373
 374        retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
 375                        IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
 376                        sizeof(u8), &partial_drain, NULL, true, true, false, false);
 377        /*
 378         * with new non blocked drain implementation in core we dont need to
 379         * wait for respsonse, and need to only invoke callback for drain
 380         * complete
 381         */
 382
 383        return retval;
 384}
 385
 386/**
 387 * sst_free_stream - Frees a stream
 388 * @str_id:             stream ID
 389 *
 390 * This function is called by any function which wants to free
 391 * a stream.
 392 */
 393int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
 394{
 395        int retval = 0;
 396        struct stream_info *str_info;
 397
 398        dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
 399
 400        mutex_lock(&sst_drv_ctx->sst_lock);
 401        if (sst_drv_ctx->sst_state == SST_RESET) {
 402                mutex_unlock(&sst_drv_ctx->sst_lock);
 403                return -ENODEV;
 404        }
 405        mutex_unlock(&sst_drv_ctx->sst_lock);
 406        str_info = get_stream_info(sst_drv_ctx, str_id);
 407        if (!str_info)
 408                return -EINVAL;
 409
 410        mutex_lock(&str_info->lock);
 411        if (str_info->status != STREAM_UN_INIT) {
 412                str_info->prev =  str_info->status;
 413                str_info->status = STREAM_UN_INIT;
 414                mutex_unlock(&str_info->lock);
 415
 416                dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
 417                                str_id, str_info->pipe_id);
 418                retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
 419                                IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
 420                                NULL, NULL, true, true, false, true);
 421
 422                dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
 423                                retval);
 424                mutex_lock(&sst_drv_ctx->sst_lock);
 425                sst_clean_stream(str_info);
 426                mutex_unlock(&sst_drv_ctx->sst_lock);
 427                dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
 428        } else {
 429                mutex_unlock(&str_info->lock);
 430                retval = -EBADRQC;
 431                dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
 432        }
 433
 434        return retval;
 435}
 436