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