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