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