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 27 int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) 28 { 29 struct snd_pcm_params *pcm_params; 30 struct snd_sst_params *str_params; 31 struct snd_sst_tstamp fw_tstamp; 32 struct stream_info *str_info; 33 int i, num_ch, str_id; 34 35 dev_dbg(sst_drv_ctx->dev, "Enter\n"); 36 37 str_params = (struct snd_sst_params *)params; 38 str_id = str_params->stream_id; 39 str_info = get_stream_info(sst_drv_ctx, str_id); 40 if (!str_info) 41 return -EINVAL; 42 43 memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param)); 44 str_info->alloc_param.operation = str_params->ops; 45 str_info->alloc_param.codec_type = str_params->codec; 46 str_info->alloc_param.sg_count = str_params->aparams.sg_count; 47 str_info->alloc_param.ring_buf_info[0].addr = 48 str_params->aparams.ring_buf_info[0].addr; 49 str_info->alloc_param.ring_buf_info[0].size = 50 str_params->aparams.ring_buf_info[0].size; 51 str_info->alloc_param.frag_size = str_params->aparams.frag_size; 52 53 memcpy(&str_info->alloc_param.codec_params, &str_params->sparams, 54 sizeof(struct snd_sst_stream_params)); 55 56 /* 57 * fill channel map params for multichannel support. 58 * Ideally channel map should be received from upper layers 59 * for multichannel support. 60 * Currently hardcoding as per FW reqm. 61 */ 62 num_ch = sst_get_num_channel(str_params); 63 pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params; 64 for (i = 0; i < 8; i++) { 65 if (i < num_ch) 66 pcm_params->channel_map[i] = i; 67 else 68 pcm_params->channel_map[i] = 0xff; 69 } 70 71 sst_drv_ctx->streams[str_id].status = STREAM_INIT; 72 sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT; 73 sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type; 74 sst_drv_ctx->streams[str_id].task_id = str_params->task; 75 sst_drv_ctx->streams[str_id].num_ch = num_ch; 76 77 if (sst_drv_ctx->info.lpe_viewpt_rqd) 78 str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start + 79 sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); 80 else 81 str_info->alloc_param.ts = sst_drv_ctx->mailbox_add + 82 sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); 83 84 dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n", 85 str_info->alloc_param.ts); 86 dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n", 87 str_info->pipe_id, str_info->task_id); 88 89 return sst_realloc_stream(sst_drv_ctx, str_id); 90 } 91 92 /** 93 * sst_realloc_stream - Send msg for (re-)allocating a stream using the 94 * @sst_drv_ctx: intel_sst_drv context pointer 95 * @str_id: stream ID 96 * 97 * Send a msg for (re-)allocating a stream using the parameters previously 98 * passed to sst_alloc_stream_mrfld() for the same stream ID. 99 * Return: 0 or negative errno value. 100 */ 101 int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 102 { 103 struct snd_sst_alloc_response *response; 104 struct stream_info *str_info; 105 void *data = NULL; 106 int ret; 107 108 str_info = get_stream_info(sst_drv_ctx, str_id); 109 if (!str_info) 110 return -EINVAL; 111 112 dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", 113 str_id, str_info->pipe_id); 114 115 ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 116 IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id, 117 sizeof(str_info->alloc_param), &str_info->alloc_param, 118 &data, true, true, false, true); 119 120 if (ret < 0) { 121 dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); 122 /* alloc failed, so reset the state to uninit */ 123 str_info->status = STREAM_UN_INIT; 124 str_id = ret; 125 } else if (data) { 126 response = (struct snd_sst_alloc_response *)data; 127 ret = response->str_type.result; 128 if (!ret) 129 goto out; 130 dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); 131 if (ret == SST_ERR_STREAM_IN_USE) { 132 dev_err(sst_drv_ctx->dev, 133 "FW not in clean state, send free for:%d\n", str_id); 134 sst_free_stream(sst_drv_ctx, str_id); 135 } 136 str_id = -ret; 137 } 138 out: 139 kfree(data); 140 return str_id; 141 } 142 143 /** 144 * sst_start_stream - Send msg for a starting stream 145 * @sst_drv_ctx: intel_sst_drv context pointer 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 * @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