18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * sst_stream.c - Intel SST Driver for audio engine 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008-14 Intel Corp 68c2ecf20Sopenharmony_ci * Authors: Vinod Koul <vinod.koul@intel.com> 78c2ecf20Sopenharmony_ci * Harsha Priya <priya.harsha@intel.com> 88c2ecf20Sopenharmony_ci * Dharageswari R <dharageswari.r@intel.com> 98c2ecf20Sopenharmony_ci * KP Jeeja <jeeja.kp@intel.com> 108c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/firmware.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <sound/core.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/soc.h> 228c2ecf20Sopenharmony_ci#include <sound/compress_driver.h> 238c2ecf20Sopenharmony_ci#include <asm/platform_sst_audio.h> 248c2ecf20Sopenharmony_ci#include "../sst-mfld-platform.h" 258c2ecf20Sopenharmony_ci#include "sst.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciint sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct snd_pcm_params *pcm_params; 308c2ecf20Sopenharmony_ci struct snd_sst_params *str_params; 318c2ecf20Sopenharmony_ci struct snd_sst_tstamp fw_tstamp; 328c2ecf20Sopenharmony_ci struct stream_info *str_info; 338c2ecf20Sopenharmony_ci int i, num_ch, str_id; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Enter\n"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci str_params = (struct snd_sst_params *)params; 388c2ecf20Sopenharmony_ci str_id = str_params->stream_id; 398c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 408c2ecf20Sopenharmony_ci if (!str_info) 418c2ecf20Sopenharmony_ci return -EINVAL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param)); 448c2ecf20Sopenharmony_ci str_info->alloc_param.operation = str_params->ops; 458c2ecf20Sopenharmony_ci str_info->alloc_param.codec_type = str_params->codec; 468c2ecf20Sopenharmony_ci str_info->alloc_param.sg_count = str_params->aparams.sg_count; 478c2ecf20Sopenharmony_ci str_info->alloc_param.ring_buf_info[0].addr = 488c2ecf20Sopenharmony_ci str_params->aparams.ring_buf_info[0].addr; 498c2ecf20Sopenharmony_ci str_info->alloc_param.ring_buf_info[0].size = 508c2ecf20Sopenharmony_ci str_params->aparams.ring_buf_info[0].size; 518c2ecf20Sopenharmony_ci str_info->alloc_param.frag_size = str_params->aparams.frag_size; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci memcpy(&str_info->alloc_param.codec_params, &str_params->sparams, 548c2ecf20Sopenharmony_ci sizeof(struct snd_sst_stream_params)); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* 578c2ecf20Sopenharmony_ci * fill channel map params for multichannel support. 588c2ecf20Sopenharmony_ci * Ideally channel map should be received from upper layers 598c2ecf20Sopenharmony_ci * for multichannel support. 608c2ecf20Sopenharmony_ci * Currently hardcoding as per FW reqm. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci num_ch = sst_get_num_channel(str_params); 638c2ecf20Sopenharmony_ci pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params; 648c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 658c2ecf20Sopenharmony_ci if (i < num_ch) 668c2ecf20Sopenharmony_ci pcm_params->channel_map[i] = i; 678c2ecf20Sopenharmony_ci else 688c2ecf20Sopenharmony_ci pcm_params->channel_map[i] = 0xff; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci sst_drv_ctx->streams[str_id].status = STREAM_INIT; 728c2ecf20Sopenharmony_ci sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT; 738c2ecf20Sopenharmony_ci sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type; 748c2ecf20Sopenharmony_ci sst_drv_ctx->streams[str_id].task_id = str_params->task; 758c2ecf20Sopenharmony_ci sst_drv_ctx->streams[str_id].num_ch = num_ch; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (sst_drv_ctx->info.lpe_viewpt_rqd) 788c2ecf20Sopenharmony_ci str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start + 798c2ecf20Sopenharmony_ci sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci str_info->alloc_param.ts = sst_drv_ctx->mailbox_add + 828c2ecf20Sopenharmony_ci sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n", 858c2ecf20Sopenharmony_ci str_info->alloc_param.ts); 868c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n", 878c2ecf20Sopenharmony_ci str_info->pipe_id, str_info->task_id); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return sst_realloc_stream(sst_drv_ctx, str_id); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/** 938c2ecf20Sopenharmony_ci * sst_realloc_stream - Send msg for (re-)allocating a stream using the 948c2ecf20Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer 958c2ecf20Sopenharmony_ci * @str_id: stream ID 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * Send a msg for (re-)allocating a stream using the parameters previously 988c2ecf20Sopenharmony_ci * passed to sst_alloc_stream_mrfld() for the same stream ID. 998c2ecf20Sopenharmony_ci * Return: 0 or negative errno value. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ciint sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct snd_sst_alloc_response *response; 1048c2ecf20Sopenharmony_ci struct stream_info *str_info; 1058c2ecf20Sopenharmony_ci void *data = NULL; 1068c2ecf20Sopenharmony_ci int ret; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 1098c2ecf20Sopenharmony_ci if (!str_info) 1108c2ecf20Sopenharmony_ci return -EINVAL; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", 1138c2ecf20Sopenharmony_ci str_id, str_info->pipe_id); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 1168c2ecf20Sopenharmony_ci IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id, 1178c2ecf20Sopenharmony_ci sizeof(str_info->alloc_param), &str_info->alloc_param, 1188c2ecf20Sopenharmony_ci &data, true, true, false, true); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (ret < 0) { 1218c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); 1228c2ecf20Sopenharmony_ci /* alloc failed, so reset the state to uninit */ 1238c2ecf20Sopenharmony_ci str_info->status = STREAM_UN_INIT; 1248c2ecf20Sopenharmony_ci str_id = ret; 1258c2ecf20Sopenharmony_ci } else if (data) { 1268c2ecf20Sopenharmony_ci response = (struct snd_sst_alloc_response *)data; 1278c2ecf20Sopenharmony_ci ret = response->str_type.result; 1288c2ecf20Sopenharmony_ci if (!ret) 1298c2ecf20Sopenharmony_ci goto out; 1308c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); 1318c2ecf20Sopenharmony_ci if (ret == SST_ERR_STREAM_IN_USE) { 1328c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, 1338c2ecf20Sopenharmony_ci "FW not in clean state, send free for:%d\n", str_id); 1348c2ecf20Sopenharmony_ci sst_free_stream(sst_drv_ctx, str_id); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci str_id = -ret; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ciout: 1398c2ecf20Sopenharmony_ci kfree(data); 1408c2ecf20Sopenharmony_ci return str_id; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/** 1448c2ecf20Sopenharmony_ci * sst_start_stream - Send msg for a starting stream 1458c2ecf20Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer 1468c2ecf20Sopenharmony_ci * @str_id: stream ID 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * This function is called by any function which wants to start 1498c2ecf20Sopenharmony_ci * a stream. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ciint sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci int retval = 0; 1548c2ecf20Sopenharmony_ci struct stream_info *str_info; 1558c2ecf20Sopenharmony_ci u16 data = 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id); 1588c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 1598c2ecf20Sopenharmony_ci if (!str_info) 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci if (str_info->status != STREAM_RUNNING) 1628c2ecf20Sopenharmony_ci return -EBADRQC; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 1658c2ecf20Sopenharmony_ci IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id, 1668c2ecf20Sopenharmony_ci sizeof(u16), &data, NULL, true, true, true, false); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return retval; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, 1728c2ecf20Sopenharmony_ci struct snd_sst_bytes_v2 *bytes) 1738c2ecf20Sopenharmony_ci{ struct ipc_post *msg = NULL; 1748c2ecf20Sopenharmony_ci u32 length; 1758c2ecf20Sopenharmony_ci int pvt_id, ret = 0; 1768c2ecf20Sopenharmony_ci struct sst_block *block = NULL; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, 1798c2ecf20Sopenharmony_ci "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n", 1808c2ecf20Sopenharmony_ci bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id, 1818c2ecf20Sopenharmony_ci bytes->pipe_id, bytes->len); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (sst_create_ipc_msg(&msg, true)) 1848c2ecf20Sopenharmony_ci return -ENOMEM; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci pvt_id = sst_assign_pvt_id(sst_drv_ctx); 1878c2ecf20Sopenharmony_ci sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg, 1888c2ecf20Sopenharmony_ci bytes->task_id, 1, pvt_id); 1898c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_high.part.res_rqd = bytes->block; 1908c2ecf20Sopenharmony_ci length = bytes->len; 1918c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_low_payload = length; 1928c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "length is %d\n", length); 1938c2ecf20Sopenharmony_ci memcpy(msg->mailbox_data, &bytes->bytes, bytes->len); 1948c2ecf20Sopenharmony_ci if (bytes->block) { 1958c2ecf20Sopenharmony_ci block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id); 1968c2ecf20Sopenharmony_ci if (block == NULL) { 1978c2ecf20Sopenharmony_ci kfree(msg); 1988c2ecf20Sopenharmony_ci ret = -ENOMEM; 1998c2ecf20Sopenharmony_ci goto out; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg); 2048c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d", 2058c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_low_payload); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (bytes->block) { 2088c2ecf20Sopenharmony_ci ret = sst_wait_timeout(sst_drv_ctx, block); 2098c2ecf20Sopenharmony_ci if (ret) { 2108c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret); 2118c2ecf20Sopenharmony_ci sst_free_block(sst_drv_ctx, block); 2128c2ecf20Sopenharmony_ci goto out; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci if (bytes->type == SND_SST_BYTES_GET) { 2168c2ecf20Sopenharmony_ci /* 2178c2ecf20Sopenharmony_ci * copy the reply and send back 2188c2ecf20Sopenharmony_ci * we need to update only sz and payload 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci if (bytes->block) { 2218c2ecf20Sopenharmony_ci unsigned char *r = block->data; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "read back %d bytes", 2248c2ecf20Sopenharmony_ci bytes->len); 2258c2ecf20Sopenharmony_ci memcpy(bytes->bytes, r, bytes->len); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci if (bytes->block) 2298c2ecf20Sopenharmony_ci sst_free_block(sst_drv_ctx, block); 2308c2ecf20Sopenharmony_ciout: 2318c2ecf20Sopenharmony_ci test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/** 2368c2ecf20Sopenharmony_ci * sst_pause_stream - Send msg for a pausing stream 2378c2ecf20Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer 2388c2ecf20Sopenharmony_ci * @str_id: stream ID 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * This function is called by any function which wants to pause 2418c2ecf20Sopenharmony_ci * an already running stream. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ciint sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int retval = 0; 2468c2ecf20Sopenharmony_ci struct stream_info *str_info; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id); 2498c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 2508c2ecf20Sopenharmony_ci if (!str_info) 2518c2ecf20Sopenharmony_ci return -EINVAL; 2528c2ecf20Sopenharmony_ci if (str_info->status == STREAM_PAUSED) 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci if (str_info->status == STREAM_RUNNING || 2558c2ecf20Sopenharmony_ci str_info->status == STREAM_INIT) { 2568c2ecf20Sopenharmony_ci if (str_info->prev == STREAM_UN_INIT) 2578c2ecf20Sopenharmony_ci return -EBADRQC; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 2608c2ecf20Sopenharmony_ci IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id, 2618c2ecf20Sopenharmony_ci 0, NULL, NULL, true, true, false, true); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (retval == 0) { 2648c2ecf20Sopenharmony_ci str_info->prev = str_info->status; 2658c2ecf20Sopenharmony_ci str_info->status = STREAM_PAUSED; 2668c2ecf20Sopenharmony_ci } else if (retval == -SST_ERR_INVALID_STREAM_ID) { 2678c2ecf20Sopenharmony_ci retval = -EINVAL; 2688c2ecf20Sopenharmony_ci mutex_lock(&sst_drv_ctx->sst_lock); 2698c2ecf20Sopenharmony_ci sst_clean_stream(str_info); 2708c2ecf20Sopenharmony_ci mutex_unlock(&sst_drv_ctx->sst_lock); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci } else { 2738c2ecf20Sopenharmony_ci retval = -EBADRQC; 2748c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n"); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return retval; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/** 2818c2ecf20Sopenharmony_ci * sst_resume_stream - Send msg for resuming stream 2828c2ecf20Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer 2838c2ecf20Sopenharmony_ci * @str_id: stream ID 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci * This function is called by any function which wants to resume 2868c2ecf20Sopenharmony_ci * an already paused stream. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ciint sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci int retval = 0; 2918c2ecf20Sopenharmony_ci struct stream_info *str_info; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id); 2948c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 2958c2ecf20Sopenharmony_ci if (!str_info) 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci if (str_info->status == STREAM_RUNNING) 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (str_info->resume_status == STREAM_PAUSED && 3018c2ecf20Sopenharmony_ci str_info->resume_prev == STREAM_RUNNING) { 3028c2ecf20Sopenharmony_ci /* 3038c2ecf20Sopenharmony_ci * Stream was running before suspend and re-created on resume, 3048c2ecf20Sopenharmony_ci * start it to get back to running state. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n"); 3078c2ecf20Sopenharmony_ci str_info->status = STREAM_RUNNING; 3088c2ecf20Sopenharmony_ci str_info->prev = STREAM_PAUSED; 3098c2ecf20Sopenharmony_ci retval = sst_start_stream(sst_drv_ctx, str_id); 3108c2ecf20Sopenharmony_ci str_info->resume_status = STREAM_UN_INIT; 3118c2ecf20Sopenharmony_ci } else if (str_info->resume_status == STREAM_PAUSED && 3128c2ecf20Sopenharmony_ci str_info->resume_prev == STREAM_INIT) { 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * Stream was idle before suspend and re-created on resume, 3158c2ecf20Sopenharmony_ci * keep it as is. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n"); 3188c2ecf20Sopenharmony_ci str_info->status = STREAM_INIT; 3198c2ecf20Sopenharmony_ci str_info->prev = STREAM_PAUSED; 3208c2ecf20Sopenharmony_ci str_info->resume_status = STREAM_UN_INIT; 3218c2ecf20Sopenharmony_ci } else if (str_info->status == STREAM_PAUSED) { 3228c2ecf20Sopenharmony_ci retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 3238c2ecf20Sopenharmony_ci IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, 3248c2ecf20Sopenharmony_ci str_info->pipe_id, 0, NULL, NULL, 3258c2ecf20Sopenharmony_ci true, true, false, true); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!retval) { 3288c2ecf20Sopenharmony_ci if (str_info->prev == STREAM_RUNNING) 3298c2ecf20Sopenharmony_ci str_info->status = STREAM_RUNNING; 3308c2ecf20Sopenharmony_ci else 3318c2ecf20Sopenharmony_ci str_info->status = STREAM_INIT; 3328c2ecf20Sopenharmony_ci str_info->prev = STREAM_PAUSED; 3338c2ecf20Sopenharmony_ci } else if (retval == -SST_ERR_INVALID_STREAM_ID) { 3348c2ecf20Sopenharmony_ci retval = -EINVAL; 3358c2ecf20Sopenharmony_ci mutex_lock(&sst_drv_ctx->sst_lock); 3368c2ecf20Sopenharmony_ci sst_clean_stream(str_info); 3378c2ecf20Sopenharmony_ci mutex_unlock(&sst_drv_ctx->sst_lock); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } else { 3408c2ecf20Sopenharmony_ci retval = -EBADRQC; 3418c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n"); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return retval; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci/** 3498c2ecf20Sopenharmony_ci * sst_drop_stream - Send msg for stopping stream 3508c2ecf20Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer 3518c2ecf20Sopenharmony_ci * @str_id: stream ID 3528c2ecf20Sopenharmony_ci * 3538c2ecf20Sopenharmony_ci * This function is called by any function which wants to stop 3548c2ecf20Sopenharmony_ci * a stream. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ciint sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci int retval = 0; 3598c2ecf20Sopenharmony_ci struct stream_info *str_info; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id); 3628c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 3638c2ecf20Sopenharmony_ci if (!str_info) 3648c2ecf20Sopenharmony_ci return -EINVAL; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (str_info->status != STREAM_UN_INIT) { 3678c2ecf20Sopenharmony_ci str_info->prev = STREAM_UN_INIT; 3688c2ecf20Sopenharmony_ci str_info->status = STREAM_INIT; 3698c2ecf20Sopenharmony_ci str_info->cumm_bytes = 0; 3708c2ecf20Sopenharmony_ci retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, 3718c2ecf20Sopenharmony_ci IPC_CMD, IPC_IA_DROP_STREAM_MRFLD, 3728c2ecf20Sopenharmony_ci str_info->pipe_id, 0, NULL, NULL, 3738c2ecf20Sopenharmony_ci true, true, true, false); 3748c2ecf20Sopenharmony_ci } else { 3758c2ecf20Sopenharmony_ci retval = -EBADRQC; 3768c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n", 3778c2ecf20Sopenharmony_ci str_info->status); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci return retval; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/** 3838c2ecf20Sopenharmony_ci * sst_drain_stream - Send msg for draining stream 3848c2ecf20Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer 3858c2ecf20Sopenharmony_ci * @str_id: stream ID 3868c2ecf20Sopenharmony_ci * @partial_drain: boolean indicating if a gapless transition is taking place 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci * This function is called by any function which wants to drain 3898c2ecf20Sopenharmony_ci * a stream. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ciint sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, 3928c2ecf20Sopenharmony_ci int str_id, bool partial_drain) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci int retval = 0; 3958c2ecf20Sopenharmony_ci struct stream_info *str_info; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id); 3988c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 3998c2ecf20Sopenharmony_ci if (!str_info) 4008c2ecf20Sopenharmony_ci return -EINVAL; 4018c2ecf20Sopenharmony_ci if (str_info->status != STREAM_RUNNING && 4028c2ecf20Sopenharmony_ci str_info->status != STREAM_INIT && 4038c2ecf20Sopenharmony_ci str_info->status != STREAM_PAUSED) { 4048c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n", 4058c2ecf20Sopenharmony_ci str_info->status); 4068c2ecf20Sopenharmony_ci return -EBADRQC; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 4108c2ecf20Sopenharmony_ci IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id, 4118c2ecf20Sopenharmony_ci sizeof(u8), &partial_drain, NULL, true, true, false, false); 4128c2ecf20Sopenharmony_ci /* 4138c2ecf20Sopenharmony_ci * with new non blocked drain implementation in core we dont need to 4148c2ecf20Sopenharmony_ci * wait for respsonse, and need to only invoke callback for drain 4158c2ecf20Sopenharmony_ci * complete 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return retval; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/** 4228c2ecf20Sopenharmony_ci * sst_free_stream - Frees a stream 4238c2ecf20Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer 4248c2ecf20Sopenharmony_ci * @str_id: stream ID 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci * This function is called by any function which wants to free 4278c2ecf20Sopenharmony_ci * a stream. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ciint sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci int retval = 0; 4328c2ecf20Sopenharmony_ci struct stream_info *str_info; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci mutex_lock(&sst_drv_ctx->sst_lock); 4378c2ecf20Sopenharmony_ci if (sst_drv_ctx->sst_state == SST_RESET) { 4388c2ecf20Sopenharmony_ci mutex_unlock(&sst_drv_ctx->sst_lock); 4398c2ecf20Sopenharmony_ci return -ENODEV; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci mutex_unlock(&sst_drv_ctx->sst_lock); 4428c2ecf20Sopenharmony_ci str_info = get_stream_info(sst_drv_ctx, str_id); 4438c2ecf20Sopenharmony_ci if (!str_info) 4448c2ecf20Sopenharmony_ci return -EINVAL; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci mutex_lock(&str_info->lock); 4478c2ecf20Sopenharmony_ci if (str_info->status != STREAM_UN_INIT) { 4488c2ecf20Sopenharmony_ci str_info->prev = str_info->status; 4498c2ecf20Sopenharmony_ci str_info->status = STREAM_UN_INIT; 4508c2ecf20Sopenharmony_ci mutex_unlock(&str_info->lock); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", 4538c2ecf20Sopenharmony_ci str_id, str_info->pipe_id); 4548c2ecf20Sopenharmony_ci retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, 4558c2ecf20Sopenharmony_ci IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, 4568c2ecf20Sopenharmony_ci NULL, NULL, true, true, false, true); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n", 4598c2ecf20Sopenharmony_ci retval); 4608c2ecf20Sopenharmony_ci mutex_lock(&sst_drv_ctx->sst_lock); 4618c2ecf20Sopenharmony_ci sst_clean_stream(str_info); 4628c2ecf20Sopenharmony_ci mutex_unlock(&sst_drv_ctx->sst_lock); 4638c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n"); 4648c2ecf20Sopenharmony_ci } else { 4658c2ecf20Sopenharmony_ci mutex_unlock(&str_info->lock); 4668c2ecf20Sopenharmony_ci retval = -EBADRQC; 4678c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n"); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci return retval; 4718c2ecf20Sopenharmony_ci} 472