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 * @sst_drv_ctx: intel_sst_drv context pointer 147 * @str_id: stream ID 148 * 149 * This function is called by any function which wants to start 150 * a stream. 151 */ 152 int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 153 { 154 int retval = 0; 155 struct stream_info *str_info; 156 u16 data = 0; 157 158 dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id); 159 str_info = get_stream_info(sst_drv_ctx, str_id); 160 if (!str_info) 161 return -EINVAL; 162 if (str_info->status != STREAM_RUNNING) 163 return -EBADRQC; 164 165 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 166 IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id, 167 sizeof(u16), &data, NULL, true, true, true, false); 168 169 return retval; 170 } 171 172 int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, 173 struct snd_sst_bytes_v2 *bytes) 174 { struct ipc_post *msg = NULL; 175 u32 length; 176 int pvt_id, ret = 0; 177 struct sst_block *block = NULL; 178 179 dev_dbg(sst_drv_ctx->dev, 180 "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n", 181 bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id, 182 bytes->pipe_id, bytes->len); 183 184 if (sst_create_ipc_msg(&msg, true)) 185 return -ENOMEM; 186 187 pvt_id = sst_assign_pvt_id(sst_drv_ctx); 188 sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg, 189 bytes->task_id, 1, pvt_id); 190 msg->mrfld_header.p.header_high.part.res_rqd = bytes->block; 191 length = bytes->len; 192 msg->mrfld_header.p.header_low_payload = length; 193 dev_dbg(sst_drv_ctx->dev, "length is %d\n", length); 194 memcpy(msg->mailbox_data, &bytes->bytes, bytes->len); 195 if (bytes->block) { 196 block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id); 197 if (block == NULL) { 198 kfree(msg); 199 ret = -ENOMEM; 200 goto out; 201 } 202 } 203 204 sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg); 205 dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d", 206 msg->mrfld_header.p.header_low_payload); 207 208 if (bytes->block) { 209 ret = sst_wait_timeout(sst_drv_ctx, block); 210 if (ret) { 211 dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret); 212 sst_free_block(sst_drv_ctx, block); 213 goto out; 214 } 215 } 216 if (bytes->type == SND_SST_BYTES_GET) { 217 /* 218 * copy the reply and send back 219 * we need to update only sz and payload 220 */ 221 if (bytes->block) { 222 unsigned char *r = block->data; 223 224 dev_dbg(sst_drv_ctx->dev, "read back %d bytes", 225 bytes->len); 226 memcpy(bytes->bytes, r, bytes->len); 227 } 228 } 229 if (bytes->block) 230 sst_free_block(sst_drv_ctx, block); 231 out: 232 test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); 233 return ret; 234 } 235 236 /** 237 * sst_pause_stream - Send msg for a pausing stream 238 * @sst_drv_ctx: intel_sst_drv context pointer 239 * @str_id: stream ID 240 * 241 * This function is called by any function which wants to pause 242 * an already running stream. 243 */ 244 int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 245 { 246 int retval = 0; 247 struct stream_info *str_info; 248 249 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id); 250 str_info = get_stream_info(sst_drv_ctx, str_id); 251 if (!str_info) 252 return -EINVAL; 253 if (str_info->status == STREAM_PAUSED) 254 return 0; 255 if (str_info->status == STREAM_RUNNING || 256 str_info->status == STREAM_INIT) { 257 if (str_info->prev == STREAM_UN_INIT) 258 return -EBADRQC; 259 260 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 261 IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id, 262 0, NULL, NULL, true, true, false, true); 263 264 if (retval == 0) { 265 str_info->prev = str_info->status; 266 str_info->status = STREAM_PAUSED; 267 } else if (retval == -SST_ERR_INVALID_STREAM_ID) { 268 retval = -EINVAL; 269 mutex_lock(&sst_drv_ctx->sst_lock); 270 sst_clean_stream(str_info); 271 mutex_unlock(&sst_drv_ctx->sst_lock); 272 } 273 } else { 274 retval = -EBADRQC; 275 dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n"); 276 } 277 278 return retval; 279 } 280 281 /** 282 * sst_resume_stream - Send msg for resuming stream 283 * @sst_drv_ctx: intel_sst_drv context pointer 284 * @str_id: stream ID 285 * 286 * This function is called by any function which wants to resume 287 * an already paused stream. 288 */ 289 int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 290 { 291 int retval = 0; 292 struct stream_info *str_info; 293 294 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id); 295 str_info = get_stream_info(sst_drv_ctx, str_id); 296 if (!str_info) 297 return -EINVAL; 298 if (str_info->status == STREAM_RUNNING) 299 return 0; 300 301 if (str_info->resume_status == STREAM_PAUSED && 302 str_info->resume_prev == STREAM_RUNNING) { 303 /* 304 * Stream was running before suspend and re-created on resume, 305 * start it to get back to running state. 306 */ 307 dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n"); 308 str_info->status = STREAM_RUNNING; 309 str_info->prev = STREAM_PAUSED; 310 retval = sst_start_stream(sst_drv_ctx, str_id); 311 str_info->resume_status = STREAM_UN_INIT; 312 } else if (str_info->resume_status == STREAM_PAUSED && 313 str_info->resume_prev == STREAM_INIT) { 314 /* 315 * Stream was idle before suspend and re-created on resume, 316 * keep it as is. 317 */ 318 dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n"); 319 str_info->status = STREAM_INIT; 320 str_info->prev = STREAM_PAUSED; 321 str_info->resume_status = STREAM_UN_INIT; 322 } else if (str_info->status == STREAM_PAUSED) { 323 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 324 IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, 325 str_info->pipe_id, 0, NULL, NULL, 326 true, true, false, true); 327 328 if (!retval) { 329 if (str_info->prev == STREAM_RUNNING) 330 str_info->status = STREAM_RUNNING; 331 else 332 str_info->status = STREAM_INIT; 333 str_info->prev = STREAM_PAUSED; 334 } else if (retval == -SST_ERR_INVALID_STREAM_ID) { 335 retval = -EINVAL; 336 mutex_lock(&sst_drv_ctx->sst_lock); 337 sst_clean_stream(str_info); 338 mutex_unlock(&sst_drv_ctx->sst_lock); 339 } 340 } else { 341 retval = -EBADRQC; 342 dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n"); 343 } 344 345 return retval; 346 } 347 348 349 /** 350 * sst_drop_stream - Send msg for stopping stream 351 * @sst_drv_ctx: intel_sst_drv context pointer 352 * @str_id: stream ID 353 * 354 * This function is called by any function which wants to stop 355 * a stream. 356 */ 357 int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 358 { 359 int retval = 0; 360 struct stream_info *str_info; 361 362 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_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 367 if (str_info->status != STREAM_UN_INIT) { 368 str_info->prev = STREAM_UN_INIT; 369 str_info->status = STREAM_INIT; 370 str_info->cumm_bytes = 0; 371 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 372 IPC_CMD, IPC_IA_DROP_STREAM_MRFLD, 373 str_info->pipe_id, 0, NULL, NULL, 374 true, true, true, false); 375 } else { 376 retval = -EBADRQC; 377 dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n", 378 str_info->status); 379 } 380 return retval; 381 } 382 383 /** 384 * sst_drain_stream - Send msg for draining stream 385 * @sst_drv_ctx: intel_sst_drv context pointer 386 * @str_id: stream ID 387 * @partial_drain: boolean indicating if a gapless transition is taking place 388 * 389 * This function is called by any function which wants to drain 390 * a stream. 391 */ 392 int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, 393 int str_id, bool partial_drain) 394 { 395 int retval = 0; 396 struct stream_info *str_info; 397 398 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id); 399 str_info = get_stream_info(sst_drv_ctx, str_id); 400 if (!str_info) 401 return -EINVAL; 402 if (str_info->status != STREAM_RUNNING && 403 str_info->status != STREAM_INIT && 404 str_info->status != STREAM_PAUSED) { 405 dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n", 406 str_info->status); 407 return -EBADRQC; 408 } 409 410 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 411 IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id, 412 sizeof(u8), &partial_drain, NULL, true, true, false, false); 413 /* 414 * with new non blocked drain implementation in core we dont need to 415 * wait for respsonse, and need to only invoke callback for drain 416 * complete 417 */ 418 419 return retval; 420 } 421 422 /** 423 * sst_free_stream - Frees a stream 424 * @sst_drv_ctx: intel_sst_drv context pointer 425 * @str_id: stream ID 426 * 427 * This function is called by any function which wants to free 428 * a stream. 429 */ 430 int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 431 { 432 int retval = 0; 433 struct stream_info *str_info; 434 435 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); 436 437 mutex_lock(&sst_drv_ctx->sst_lock); 438 if (sst_drv_ctx->sst_state == SST_RESET) { 439 mutex_unlock(&sst_drv_ctx->sst_lock); 440 return -ENODEV; 441 } 442 mutex_unlock(&sst_drv_ctx->sst_lock); 443 str_info = get_stream_info(sst_drv_ctx, str_id); 444 if (!str_info) 445 return -EINVAL; 446 447 mutex_lock(&str_info->lock); 448 if (str_info->status != STREAM_UN_INIT) { 449 str_info->prev = str_info->status; 450 str_info->status = STREAM_UN_INIT; 451 mutex_unlock(&str_info->lock); 452 453 dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", 454 str_id, str_info->pipe_id); 455 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 456 IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, 457 NULL, NULL, true, true, false, true); 458 459 dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n", 460 retval); 461 mutex_lock(&sst_drv_ctx->sst_lock); 462 sst_clean_stream(str_info); 463 mutex_unlock(&sst_drv_ctx->sst_lock); 464 dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n"); 465 } else { 466 mutex_unlock(&str_info->lock); 467 retval = -EBADRQC; 468 dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n"); 469 } 470 471 return retval; 472 } 473