root/sound/soc/intel/atom/sst/sst_stream.c

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

DEFINITIONS

This source file includes following definitions.
  1. sst_alloc_stream_mrfld
  2. sst_realloc_stream
  3. sst_start_stream
  4. sst_send_byte_stream_mrfld
  5. sst_pause_stream
  6. sst_resume_stream
  7. sst_drop_stream
  8. sst_drain_stream
  9. sst_free_stream

   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 
  28 int 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  */
 102 int 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         }
 139 out:
 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 */
 151 int 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 
 171 int 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);
 230 out:
 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  */
 242 int 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  */
 286 int 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  */
 353 int 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 */
 386 int 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  */
 423 int 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 }

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