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 <sound/core.h> 19 #include <sound/pcm.h> 20 #include <sound/soc.h> 21 #include <sound/compress_driver.h> 22 #include <asm/platform_sst_audio.h> 23 #include "../sst-mfld-platform.h" 24 #include "sst.h" 25 26 int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) 27 { 28 struct snd_pcm_params *pcm_params; 29 struct snd_sst_params *str_params; 30 struct snd_sst_tstamp fw_tstamp; 31 struct stream_info *str_info; 32 int i, num_ch, str_id; 33 34 dev_dbg(sst_drv_ctx->dev, "Enter\n"); 35 36 str_params = (struct snd_sst_params *)params; 37 str_id = str_params->stream_id; 38 str_info = get_stream_info(sst_drv_ctx, str_id); 39 if (!str_info) 40 return -EINVAL; 41 42 memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param)); 43 str_info->alloc_param.operation = str_params->ops; 44 str_info->alloc_param.codec_type = str_params->codec; 45 str_info->alloc_param.sg_count = str_params->aparams.sg_count; 46 str_info->alloc_param.ring_buf_info[0].addr = 47 str_params->aparams.ring_buf_info[0].addr; 48 str_info->alloc_param.ring_buf_info[0].size = 49 str_params->aparams.ring_buf_info[0].size; 50 str_info->alloc_param.frag_size = str_params->aparams.frag_size; 51 52 memcpy(&str_info->alloc_param.codec_params, &str_params->sparams, 53 sizeof(struct snd_sst_stream_params)); 54 55 /* 56 * fill channel map params for multichannel support. 57 * Ideally channel map should be received from upper layers 58 * for multichannel support. 59 * Currently hardcoding as per FW reqm. 60 */ 61 num_ch = sst_get_num_channel(str_params); 62 pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params; 63 for (i = 0; i < 8; i++) { 64 if (i < num_ch) 65 pcm_params->channel_map[i] = i; 66 else 67 pcm_params->channel_map[i] = 0xff; 68 } 69 70 sst_drv_ctx->streams[str_id].status = STREAM_INIT; 71 sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT; 72 sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type; 73 sst_drv_ctx->streams[str_id].task_id = str_params->task; 74 sst_drv_ctx->streams[str_id].num_ch = num_ch; 75 76 if (sst_drv_ctx->info.lpe_viewpt_rqd) 77 str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start + 78 sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); 79 else 80 str_info->alloc_param.ts = sst_drv_ctx->mailbox_add + 81 sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); 82 83 dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n", 84 str_info->alloc_param.ts); 85 dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n", 86 str_info->pipe_id, str_info->task_id); 87 88 return sst_realloc_stream(sst_drv_ctx, str_id); 89 } 90 91 /** 92 * sst_realloc_stream - Send msg for (re-)allocating a stream using the 93 * @sst_drv_ctx: intel_sst_drv context pointer 94 * @str_id: stream ID 95 * 96 * Send a msg for (re-)allocating a stream using the parameters previously 97 * passed to sst_alloc_stream_mrfld() for the same stream ID. 98 * Return: 0 or negative errno value. 99 */ 100 int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 101 { 102 struct snd_sst_alloc_response *response; 103 struct stream_info *str_info; 104 void *data = NULL; 105 int ret; 106 107 str_info = get_stream_info(sst_drv_ctx, str_id); 108 if (!str_info) 109 return -EINVAL; 110 111 dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", 112 str_id, str_info->pipe_id); 113 114 ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 115 IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id, 116 sizeof(str_info->alloc_param), &str_info->alloc_param, 117 &data, true, true, false, true); 118 119 if (ret < 0) { 120 dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); 121 /* alloc failed, so reset the state to uninit */ 122 str_info->status = STREAM_UN_INIT; 123 str_id = ret; 124 } else if (data) { 125 response = (struct snd_sst_alloc_response *)data; 126 ret = response->str_type.result; 127 if (!ret) 128 goto out; 129 dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); 130 if (ret == SST_ERR_STREAM_IN_USE) { 131 dev_err(sst_drv_ctx->dev, 132 "FW not in clean state, send free for:%d\n", str_id); 133 sst_free_stream(sst_drv_ctx, str_id); 134 } 135 str_id = -ret; 136 } 137 out: 138 kfree(data); 139 return str_id; 140 } 141 142 /** 143 * sst_start_stream - Send msg for a starting stream 144 * @sst_drv_ctx: intel_sst_drv context pointer 145 * @str_id: stream ID 146 * 147 * This function is called by any function which wants to start 148 * a stream. 149 */ 150 int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 151 { 152 int retval = 0; 153 struct stream_info *str_info; 154 u16 data = 0; 155 156 dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id); 157 str_info = get_stream_info(sst_drv_ctx, str_id); 158 if (!str_info) 159 return -EINVAL; 160 if (str_info->status != STREAM_RUNNING) 161 return -EBADRQC; 162 163 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 164 IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id, 165 sizeof(u16), &data, NULL, true, true, true, false); 166 167 return retval; 168 } 169 170 int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, 171 struct snd_sst_bytes_v2 *bytes) 172 { struct ipc_post *msg = NULL; 173 u32 length; 174 int pvt_id, ret = 0; 175 struct sst_block *block = NULL; 176 u8 bytes_block = bytes->block; 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 * @sst_drv_ctx: intel_sst_drv context pointer 238 * @str_id: stream ID 239 * 240 * This function is called by any function which wants to pause 241 * an already running stream. 242 */ 243 int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 244 { 245 int retval = 0; 246 struct stream_info *str_info; 247 248 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id); 249 str_info = get_stream_info(sst_drv_ctx, str_id); 250 if (!str_info) 251 return -EINVAL; 252 if (str_info->status == STREAM_PAUSED) 253 return 0; 254 if (str_info->status == STREAM_RUNNING || 255 str_info->status == STREAM_INIT) { 256 if (str_info->prev == STREAM_UN_INIT) 257 return -EBADRQC; 258 259 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 260 IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id, 261 0, NULL, NULL, true, true, false, true); 262 263 if (retval == 0) { 264 str_info->prev = str_info->status; 265 str_info->status = STREAM_PAUSED; 266 } else if (retval == -SST_ERR_INVALID_STREAM_ID) { 267 retval = -EINVAL; 268 mutex_lock(&sst_drv_ctx->sst_lock); 269 sst_clean_stream(str_info); 270 mutex_unlock(&sst_drv_ctx->sst_lock); 271 } 272 } else { 273 retval = -EBADRQC; 274 dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n"); 275 } 276 277 return retval; 278 } 279 280 /** 281 * sst_resume_stream - Send msg for resuming stream 282 * @sst_drv_ctx: intel_sst_drv context pointer 283 * @str_id: stream ID 284 * 285 * This function is called by any function which wants to resume 286 * an already paused stream. 287 */ 288 int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 289 { 290 int retval = 0; 291 struct stream_info *str_info; 292 293 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id); 294 str_info = get_stream_info(sst_drv_ctx, str_id); 295 if (!str_info) 296 return -EINVAL; 297 if (str_info->status == STREAM_RUNNING) 298 return 0; 299 300 if (str_info->resume_status == STREAM_PAUSED && 301 str_info->resume_prev == STREAM_RUNNING) { 302 /* 303 * Stream was running before suspend and re-created on resume, 304 * start it to get back to running state. 305 */ 306 dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n"); 307 str_info->status = STREAM_RUNNING; 308 str_info->prev = STREAM_PAUSED; 309 retval = sst_start_stream(sst_drv_ctx, str_id); 310 str_info->resume_status = STREAM_UN_INIT; 311 } else if (str_info->resume_status == STREAM_PAUSED && 312 str_info->resume_prev == STREAM_INIT) { 313 /* 314 * Stream was idle before suspend and re-created on resume, 315 * keep it as is. 316 */ 317 dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n"); 318 str_info->status = STREAM_INIT; 319 str_info->prev = STREAM_PAUSED; 320 str_info->resume_status = STREAM_UN_INIT; 321 } else if (str_info->status == STREAM_PAUSED) { 322 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 323 IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, 324 str_info->pipe_id, 0, NULL, NULL, 325 true, true, false, true); 326 327 if (!retval) { 328 if (str_info->prev == STREAM_RUNNING) 329 str_info->status = STREAM_RUNNING; 330 else 331 str_info->status = STREAM_INIT; 332 str_info->prev = STREAM_PAUSED; 333 } else if (retval == -SST_ERR_INVALID_STREAM_ID) { 334 retval = -EINVAL; 335 mutex_lock(&sst_drv_ctx->sst_lock); 336 sst_clean_stream(str_info); 337 mutex_unlock(&sst_drv_ctx->sst_lock); 338 } 339 } else { 340 retval = -EBADRQC; 341 dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n"); 342 } 343 344 return retval; 345 } 346 347 348 /** 349 * sst_drop_stream - Send msg for stopping stream 350 * @sst_drv_ctx: intel_sst_drv context pointer 351 * @str_id: stream ID 352 * 353 * This function is called by any function which wants to stop 354 * a stream. 355 */ 356 int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 357 { 358 int retval = 0; 359 struct stream_info *str_info; 360 361 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id); 362 str_info = get_stream_info(sst_drv_ctx, str_id); 363 if (!str_info) 364 return -EINVAL; 365 366 if (str_info->status != STREAM_UN_INIT) { 367 str_info->prev = STREAM_UN_INIT; 368 str_info->status = STREAM_INIT; 369 str_info->cumm_bytes = 0; 370 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 371 IPC_CMD, IPC_IA_DROP_STREAM_MRFLD, 372 str_info->pipe_id, 0, NULL, NULL, 373 true, true, true, false); 374 } else { 375 retval = -EBADRQC; 376 dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n", 377 str_info->status); 378 } 379 return retval; 380 } 381 382 /** 383 * sst_drain_stream - Send msg for draining stream 384 * @sst_drv_ctx: intel_sst_drv context pointer 385 * @str_id: stream ID 386 * @partial_drain: boolean indicating if a gapless transition is taking place 387 * 388 * This function is called by any function which wants to drain 389 * a stream. 390 */ 391 int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, 392 int str_id, bool partial_drain) 393 { 394 int retval = 0; 395 struct stream_info *str_info; 396 397 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id); 398 str_info = get_stream_info(sst_drv_ctx, str_id); 399 if (!str_info) 400 return -EINVAL; 401 if (str_info->status != STREAM_RUNNING && 402 str_info->status != STREAM_INIT && 403 str_info->status != STREAM_PAUSED) { 404 dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n", 405 str_info->status); 406 return -EBADRQC; 407 } 408 409 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 410 IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id, 411 sizeof(u8), &partial_drain, NULL, true, true, false, false); 412 /* 413 * with new non blocked drain implementation in core we dont need to 414 * wait for respsonse, and need to only invoke callback for drain 415 * complete 416 */ 417 418 return retval; 419 } 420 421 /** 422 * sst_free_stream - Frees a stream 423 * @sst_drv_ctx: intel_sst_drv context pointer 424 * @str_id: stream ID 425 * 426 * This function is called by any function which wants to free 427 * a stream. 428 */ 429 int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 430 { 431 int retval = 0; 432 struct stream_info *str_info; 433 434 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); 435 436 mutex_lock(&sst_drv_ctx->sst_lock); 437 if (sst_drv_ctx->sst_state == SST_RESET) { 438 mutex_unlock(&sst_drv_ctx->sst_lock); 439 return -ENODEV; 440 } 441 mutex_unlock(&sst_drv_ctx->sst_lock); 442 str_info = get_stream_info(sst_drv_ctx, str_id); 443 if (!str_info) 444 return -EINVAL; 445 446 mutex_lock(&str_info->lock); 447 if (str_info->status != STREAM_UN_INIT) { 448 str_info->prev = str_info->status; 449 str_info->status = STREAM_UN_INIT; 450 mutex_unlock(&str_info->lock); 451 452 dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", 453 str_id, str_info->pipe_id); 454 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 455 IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, 456 NULL, NULL, true, true, false, true); 457 458 dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n", 459 retval); 460 mutex_lock(&sst_drv_ctx->sst_lock); 461 sst_clean_stream(str_info); 462 mutex_unlock(&sst_drv_ctx->sst_lock); 463 dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n"); 464 } else { 465 mutex_unlock(&str_info->lock); 466 retval = -EBADRQC; 467 dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n"); 468 } 469 470 return retval; 471 } 472