162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  sst_stream.c - Intel SST Driver for audio engine
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2008-14 Intel Corp
662306a36Sopenharmony_ci *  Authors:	Vinod Koul <vinod.koul@intel.com>
762306a36Sopenharmony_ci *		Harsha Priya <priya.harsha@intel.com>
862306a36Sopenharmony_ci *		Dharageswari R <dharageswari.r@intel.com>
962306a36Sopenharmony_ci *		KP Jeeja <jeeja.kp@intel.com>
1062306a36Sopenharmony_ci *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci#include <linux/pci.h>
1562306a36Sopenharmony_ci#include <linux/firmware.h>
1662306a36Sopenharmony_ci#include <linux/sched.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <sound/core.h>
1962306a36Sopenharmony_ci#include <sound/pcm.h>
2062306a36Sopenharmony_ci#include <sound/soc.h>
2162306a36Sopenharmony_ci#include <sound/compress_driver.h>
2262306a36Sopenharmony_ci#include <asm/platform_sst_audio.h>
2362306a36Sopenharmony_ci#include "../sst-mfld-platform.h"
2462306a36Sopenharmony_ci#include "sst.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciint sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct snd_pcm_params *pcm_params;
2962306a36Sopenharmony_ci	struct snd_sst_params *str_params;
3062306a36Sopenharmony_ci	struct snd_sst_tstamp fw_tstamp;
3162306a36Sopenharmony_ci	struct stream_info *str_info;
3262306a36Sopenharmony_ci	int i, num_ch, str_id;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "Enter\n");
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	str_params = (struct snd_sst_params *)params;
3762306a36Sopenharmony_ci	str_id = str_params->stream_id;
3862306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
3962306a36Sopenharmony_ci	if (!str_info)
4062306a36Sopenharmony_ci		return -EINVAL;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param));
4362306a36Sopenharmony_ci	str_info->alloc_param.operation = str_params->ops;
4462306a36Sopenharmony_ci	str_info->alloc_param.codec_type = str_params->codec;
4562306a36Sopenharmony_ci	str_info->alloc_param.sg_count = str_params->aparams.sg_count;
4662306a36Sopenharmony_ci	str_info->alloc_param.ring_buf_info[0].addr =
4762306a36Sopenharmony_ci		str_params->aparams.ring_buf_info[0].addr;
4862306a36Sopenharmony_ci	str_info->alloc_param.ring_buf_info[0].size =
4962306a36Sopenharmony_ci		str_params->aparams.ring_buf_info[0].size;
5062306a36Sopenharmony_ci	str_info->alloc_param.frag_size = str_params->aparams.frag_size;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	memcpy(&str_info->alloc_param.codec_params, &str_params->sparams,
5362306a36Sopenharmony_ci			sizeof(struct snd_sst_stream_params));
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/*
5662306a36Sopenharmony_ci	 * fill channel map params for multichannel support.
5762306a36Sopenharmony_ci	 * Ideally channel map should be received from upper layers
5862306a36Sopenharmony_ci	 * for multichannel support.
5962306a36Sopenharmony_ci	 * Currently hardcoding as per FW reqm.
6062306a36Sopenharmony_ci	 */
6162306a36Sopenharmony_ci	num_ch = sst_get_num_channel(str_params);
6262306a36Sopenharmony_ci	pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params;
6362306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
6462306a36Sopenharmony_ci		if (i < num_ch)
6562306a36Sopenharmony_ci			pcm_params->channel_map[i] = i;
6662306a36Sopenharmony_ci		else
6762306a36Sopenharmony_ci			pcm_params->channel_map[i] = 0xff;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	sst_drv_ctx->streams[str_id].status = STREAM_INIT;
7162306a36Sopenharmony_ci	sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT;
7262306a36Sopenharmony_ci	sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type;
7362306a36Sopenharmony_ci	sst_drv_ctx->streams[str_id].task_id = str_params->task;
7462306a36Sopenharmony_ci	sst_drv_ctx->streams[str_id].num_ch = num_ch;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (sst_drv_ctx->info.lpe_viewpt_rqd)
7762306a36Sopenharmony_ci		str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start +
7862306a36Sopenharmony_ci			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
7962306a36Sopenharmony_ci	else
8062306a36Sopenharmony_ci		str_info->alloc_param.ts = sst_drv_ctx->mailbox_add +
8162306a36Sopenharmony_ci			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
8462306a36Sopenharmony_ci			str_info->alloc_param.ts);
8562306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
8662306a36Sopenharmony_ci			str_info->pipe_id, str_info->task_id);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return sst_realloc_stream(sst_drv_ctx, str_id);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/**
9262306a36Sopenharmony_ci * sst_realloc_stream - Send msg for (re-)allocating a stream using the
9362306a36Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer
9462306a36Sopenharmony_ci * @str_id: stream ID
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Send a msg for (re-)allocating a stream using the parameters previously
9762306a36Sopenharmony_ci * passed to sst_alloc_stream_mrfld() for the same stream ID.
9862306a36Sopenharmony_ci * Return: 0 or negative errno value.
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_ciint sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct snd_sst_alloc_response *response;
10362306a36Sopenharmony_ci	struct stream_info *str_info;
10462306a36Sopenharmony_ci	void *data = NULL;
10562306a36Sopenharmony_ci	int ret;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
10862306a36Sopenharmony_ci	if (!str_info)
10962306a36Sopenharmony_ci		return -EINVAL;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
11262306a36Sopenharmony_ci		str_id, str_info->pipe_id);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
11562306a36Sopenharmony_ci			IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id,
11662306a36Sopenharmony_ci			sizeof(str_info->alloc_param), &str_info->alloc_param,
11762306a36Sopenharmony_ci			&data, true, true, false, true);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (ret < 0) {
12062306a36Sopenharmony_ci		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
12162306a36Sopenharmony_ci		/* alloc failed, so reset the state to uninit */
12262306a36Sopenharmony_ci		str_info->status = STREAM_UN_INIT;
12362306a36Sopenharmony_ci		str_id = ret;
12462306a36Sopenharmony_ci	} else if (data) {
12562306a36Sopenharmony_ci		response = (struct snd_sst_alloc_response *)data;
12662306a36Sopenharmony_ci		ret = response->str_type.result;
12762306a36Sopenharmony_ci		if (!ret)
12862306a36Sopenharmony_ci			goto out;
12962306a36Sopenharmony_ci		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
13062306a36Sopenharmony_ci		if (ret == SST_ERR_STREAM_IN_USE) {
13162306a36Sopenharmony_ci			dev_err(sst_drv_ctx->dev,
13262306a36Sopenharmony_ci				"FW not in clean state, send free for:%d\n", str_id);
13362306a36Sopenharmony_ci			sst_free_stream(sst_drv_ctx, str_id);
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci		str_id = -ret;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ciout:
13862306a36Sopenharmony_ci	kfree(data);
13962306a36Sopenharmony_ci	return str_id;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/**
14362306a36Sopenharmony_ci * sst_start_stream - Send msg for a starting stream
14462306a36Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer
14562306a36Sopenharmony_ci * @str_id: stream ID
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * This function is called by any function which wants to start
14862306a36Sopenharmony_ci * a stream.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_ciint sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	int retval = 0;
15362306a36Sopenharmony_ci	struct stream_info *str_info;
15462306a36Sopenharmony_ci	u16 data = 0;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id);
15762306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
15862306a36Sopenharmony_ci	if (!str_info)
15962306a36Sopenharmony_ci		return -EINVAL;
16062306a36Sopenharmony_ci	if (str_info->status != STREAM_RUNNING)
16162306a36Sopenharmony_ci		return -EBADRQC;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
16462306a36Sopenharmony_ci			IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id,
16562306a36Sopenharmony_ci			sizeof(u16), &data, NULL, true, true, true, false);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return retval;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ciint sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
17162306a36Sopenharmony_ci		struct snd_sst_bytes_v2 *bytes)
17262306a36Sopenharmony_ci{	struct ipc_post *msg = NULL;
17362306a36Sopenharmony_ci	u32 length;
17462306a36Sopenharmony_ci	int pvt_id, ret = 0;
17562306a36Sopenharmony_ci	struct sst_block *block = NULL;
17662306a36Sopenharmony_ci	u8 bytes_block = bytes->block;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev,
17962306a36Sopenharmony_ci		"type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
18062306a36Sopenharmony_ci		bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id,
18162306a36Sopenharmony_ci		bytes->pipe_id, bytes->len);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (sst_create_ipc_msg(&msg, true))
18462306a36Sopenharmony_ci		return -ENOMEM;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	pvt_id = sst_assign_pvt_id(sst_drv_ctx);
18762306a36Sopenharmony_ci	sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
18862306a36Sopenharmony_ci			bytes->task_id, 1, pvt_id);
18962306a36Sopenharmony_ci	msg->mrfld_header.p.header_high.part.res_rqd = bytes_block;
19062306a36Sopenharmony_ci	length = bytes->len;
19162306a36Sopenharmony_ci	msg->mrfld_header.p.header_low_payload = length;
19262306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
19362306a36Sopenharmony_ci	memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
19462306a36Sopenharmony_ci	if (bytes_block) {
19562306a36Sopenharmony_ci		block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
19662306a36Sopenharmony_ci		if (block == NULL) {
19762306a36Sopenharmony_ci			kfree(msg);
19862306a36Sopenharmony_ci			ret = -ENOMEM;
19962306a36Sopenharmony_ci			goto out;
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
20462306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
20562306a36Sopenharmony_ci			msg->mrfld_header.p.header_low_payload);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (bytes_block) {
20862306a36Sopenharmony_ci		ret = sst_wait_timeout(sst_drv_ctx, block);
20962306a36Sopenharmony_ci		if (ret) {
21062306a36Sopenharmony_ci			dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
21162306a36Sopenharmony_ci			sst_free_block(sst_drv_ctx, block);
21262306a36Sopenharmony_ci			goto out;
21362306a36Sopenharmony_ci		}
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci	if (bytes->type == SND_SST_BYTES_GET) {
21662306a36Sopenharmony_ci		/*
21762306a36Sopenharmony_ci		 * copy the reply and send back
21862306a36Sopenharmony_ci		 * we need to update only sz and payload
21962306a36Sopenharmony_ci		 */
22062306a36Sopenharmony_ci		if (bytes_block) {
22162306a36Sopenharmony_ci			unsigned char *r = block->data;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci			dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
22462306a36Sopenharmony_ci					bytes->len);
22562306a36Sopenharmony_ci			memcpy(bytes->bytes, r, bytes->len);
22662306a36Sopenharmony_ci		}
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci	if (bytes_block)
22962306a36Sopenharmony_ci		sst_free_block(sst_drv_ctx, block);
23062306a36Sopenharmony_ciout:
23162306a36Sopenharmony_ci	test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
23262306a36Sopenharmony_ci	return ret;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/**
23662306a36Sopenharmony_ci * sst_pause_stream - Send msg for a pausing stream
23762306a36Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer
23862306a36Sopenharmony_ci * @str_id: stream ID
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * This function is called by any function which wants to pause
24162306a36Sopenharmony_ci * an already running stream.
24262306a36Sopenharmony_ci */
24362306a36Sopenharmony_ciint sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int retval = 0;
24662306a36Sopenharmony_ci	struct stream_info *str_info;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
24962306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
25062306a36Sopenharmony_ci	if (!str_info)
25162306a36Sopenharmony_ci		return -EINVAL;
25262306a36Sopenharmony_ci	if (str_info->status == STREAM_PAUSED)
25362306a36Sopenharmony_ci		return 0;
25462306a36Sopenharmony_ci	if (str_info->status == STREAM_RUNNING ||
25562306a36Sopenharmony_ci		str_info->status == STREAM_INIT) {
25662306a36Sopenharmony_ci		if (str_info->prev == STREAM_UN_INIT)
25762306a36Sopenharmony_ci			return -EBADRQC;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
26062306a36Sopenharmony_ci				IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
26162306a36Sopenharmony_ci				0, NULL, NULL, true, true, false, true);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (retval == 0) {
26462306a36Sopenharmony_ci			str_info->prev = str_info->status;
26562306a36Sopenharmony_ci			str_info->status = STREAM_PAUSED;
26662306a36Sopenharmony_ci		} else if (retval == -SST_ERR_INVALID_STREAM_ID) {
26762306a36Sopenharmony_ci			retval = -EINVAL;
26862306a36Sopenharmony_ci			mutex_lock(&sst_drv_ctx->sst_lock);
26962306a36Sopenharmony_ci			sst_clean_stream(str_info);
27062306a36Sopenharmony_ci			mutex_unlock(&sst_drv_ctx->sst_lock);
27162306a36Sopenharmony_ci		}
27262306a36Sopenharmony_ci	} else {
27362306a36Sopenharmony_ci		retval = -EBADRQC;
27462306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n");
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return retval;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci/**
28162306a36Sopenharmony_ci * sst_resume_stream - Send msg for resuming stream
28262306a36Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer
28362306a36Sopenharmony_ci * @str_id: stream ID
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci * This function is called by any function which wants to resume
28662306a36Sopenharmony_ci * an already paused stream.
28762306a36Sopenharmony_ci */
28862306a36Sopenharmony_ciint sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	int retval = 0;
29162306a36Sopenharmony_ci	struct stream_info *str_info;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
29462306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
29562306a36Sopenharmony_ci	if (!str_info)
29662306a36Sopenharmony_ci		return -EINVAL;
29762306a36Sopenharmony_ci	if (str_info->status == STREAM_RUNNING)
29862306a36Sopenharmony_ci		return 0;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (str_info->resume_status == STREAM_PAUSED &&
30162306a36Sopenharmony_ci	    str_info->resume_prev == STREAM_RUNNING) {
30262306a36Sopenharmony_ci		/*
30362306a36Sopenharmony_ci		 * Stream was running before suspend and re-created on resume,
30462306a36Sopenharmony_ci		 * start it to get back to running state.
30562306a36Sopenharmony_ci		 */
30662306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n");
30762306a36Sopenharmony_ci		str_info->status = STREAM_RUNNING;
30862306a36Sopenharmony_ci		str_info->prev = STREAM_PAUSED;
30962306a36Sopenharmony_ci		retval = sst_start_stream(sst_drv_ctx, str_id);
31062306a36Sopenharmony_ci		str_info->resume_status = STREAM_UN_INIT;
31162306a36Sopenharmony_ci	} else if (str_info->resume_status == STREAM_PAUSED &&
31262306a36Sopenharmony_ci		   str_info->resume_prev == STREAM_INIT) {
31362306a36Sopenharmony_ci		/*
31462306a36Sopenharmony_ci		 * Stream was idle before suspend and re-created on resume,
31562306a36Sopenharmony_ci		 * keep it as is.
31662306a36Sopenharmony_ci		 */
31762306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n");
31862306a36Sopenharmony_ci		str_info->status = STREAM_INIT;
31962306a36Sopenharmony_ci		str_info->prev = STREAM_PAUSED;
32062306a36Sopenharmony_ci		str_info->resume_status = STREAM_UN_INIT;
32162306a36Sopenharmony_ci	} else if (str_info->status == STREAM_PAUSED) {
32262306a36Sopenharmony_ci		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
32362306a36Sopenharmony_ci				IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
32462306a36Sopenharmony_ci				str_info->pipe_id, 0, NULL, NULL,
32562306a36Sopenharmony_ci				true, true, false, true);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		if (!retval) {
32862306a36Sopenharmony_ci			if (str_info->prev == STREAM_RUNNING)
32962306a36Sopenharmony_ci				str_info->status = STREAM_RUNNING;
33062306a36Sopenharmony_ci			else
33162306a36Sopenharmony_ci				str_info->status = STREAM_INIT;
33262306a36Sopenharmony_ci			str_info->prev = STREAM_PAUSED;
33362306a36Sopenharmony_ci		} else if (retval == -SST_ERR_INVALID_STREAM_ID) {
33462306a36Sopenharmony_ci			retval = -EINVAL;
33562306a36Sopenharmony_ci			mutex_lock(&sst_drv_ctx->sst_lock);
33662306a36Sopenharmony_ci			sst_clean_stream(str_info);
33762306a36Sopenharmony_ci			mutex_unlock(&sst_drv_ctx->sst_lock);
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci	} else {
34062306a36Sopenharmony_ci		retval = -EBADRQC;
34162306a36Sopenharmony_ci		dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return retval;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * sst_drop_stream - Send msg for stopping stream
35062306a36Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer
35162306a36Sopenharmony_ci * @str_id: stream ID
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * This function is called by any function which wants to stop
35462306a36Sopenharmony_ci * a stream.
35562306a36Sopenharmony_ci */
35662306a36Sopenharmony_ciint sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	int retval = 0;
35962306a36Sopenharmony_ci	struct stream_info *str_info;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
36262306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
36362306a36Sopenharmony_ci	if (!str_info)
36462306a36Sopenharmony_ci		return -EINVAL;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (str_info->status != STREAM_UN_INIT) {
36762306a36Sopenharmony_ci		str_info->prev = STREAM_UN_INIT;
36862306a36Sopenharmony_ci		str_info->status = STREAM_INIT;
36962306a36Sopenharmony_ci		str_info->cumm_bytes = 0;
37062306a36Sopenharmony_ci		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
37162306a36Sopenharmony_ci				IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
37262306a36Sopenharmony_ci				str_info->pipe_id, 0, NULL, NULL,
37362306a36Sopenharmony_ci				true, true, true, false);
37462306a36Sopenharmony_ci	} else {
37562306a36Sopenharmony_ci		retval = -EBADRQC;
37662306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
37762306a36Sopenharmony_ci				str_info->status);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci	return retval;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci/**
38362306a36Sopenharmony_ci * sst_drain_stream - Send msg for draining stream
38462306a36Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer
38562306a36Sopenharmony_ci * @str_id: stream ID
38662306a36Sopenharmony_ci * @partial_drain: boolean indicating if a gapless transition is taking place
38762306a36Sopenharmony_ci *
38862306a36Sopenharmony_ci * This function is called by any function which wants to drain
38962306a36Sopenharmony_ci * a stream.
39062306a36Sopenharmony_ci */
39162306a36Sopenharmony_ciint sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
39262306a36Sopenharmony_ci			int str_id, bool partial_drain)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	int retval = 0;
39562306a36Sopenharmony_ci	struct stream_info *str_info;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id);
39862306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
39962306a36Sopenharmony_ci	if (!str_info)
40062306a36Sopenharmony_ci		return -EINVAL;
40162306a36Sopenharmony_ci	if (str_info->status != STREAM_RUNNING &&
40262306a36Sopenharmony_ci		str_info->status != STREAM_INIT &&
40362306a36Sopenharmony_ci		str_info->status != STREAM_PAUSED) {
40462306a36Sopenharmony_ci			dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
40562306a36Sopenharmony_ci				       str_info->status);
40662306a36Sopenharmony_ci			return -EBADRQC;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
41062306a36Sopenharmony_ci			IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
41162306a36Sopenharmony_ci			sizeof(u8), &partial_drain, NULL, true, true, false, false);
41262306a36Sopenharmony_ci	/*
41362306a36Sopenharmony_ci	 * with new non blocked drain implementation in core we dont need to
41462306a36Sopenharmony_ci	 * wait for respsonse, and need to only invoke callback for drain
41562306a36Sopenharmony_ci	 * complete
41662306a36Sopenharmony_ci	 */
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return retval;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/**
42262306a36Sopenharmony_ci * sst_free_stream - Frees a stream
42362306a36Sopenharmony_ci * @sst_drv_ctx: intel_sst_drv context pointer
42462306a36Sopenharmony_ci * @str_id: stream ID
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * This function is called by any function which wants to free
42762306a36Sopenharmony_ci * a stream.
42862306a36Sopenharmony_ci */
42962306a36Sopenharmony_ciint sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	int retval = 0;
43262306a36Sopenharmony_ci	struct stream_info *str_info;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	mutex_lock(&sst_drv_ctx->sst_lock);
43762306a36Sopenharmony_ci	if (sst_drv_ctx->sst_state == SST_RESET) {
43862306a36Sopenharmony_ci		mutex_unlock(&sst_drv_ctx->sst_lock);
43962306a36Sopenharmony_ci		return -ENODEV;
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci	mutex_unlock(&sst_drv_ctx->sst_lock);
44262306a36Sopenharmony_ci	str_info = get_stream_info(sst_drv_ctx, str_id);
44362306a36Sopenharmony_ci	if (!str_info)
44462306a36Sopenharmony_ci		return -EINVAL;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	mutex_lock(&str_info->lock);
44762306a36Sopenharmony_ci	if (str_info->status != STREAM_UN_INIT) {
44862306a36Sopenharmony_ci		str_info->prev =  str_info->status;
44962306a36Sopenharmony_ci		str_info->status = STREAM_UN_INIT;
45062306a36Sopenharmony_ci		mutex_unlock(&str_info->lock);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
45362306a36Sopenharmony_ci				str_id, str_info->pipe_id);
45462306a36Sopenharmony_ci		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
45562306a36Sopenharmony_ci				IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
45662306a36Sopenharmony_ci				NULL, NULL, true, true, false, true);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
45962306a36Sopenharmony_ci				retval);
46062306a36Sopenharmony_ci		mutex_lock(&sst_drv_ctx->sst_lock);
46162306a36Sopenharmony_ci		sst_clean_stream(str_info);
46262306a36Sopenharmony_ci		mutex_unlock(&sst_drv_ctx->sst_lock);
46362306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
46462306a36Sopenharmony_ci	} else {
46562306a36Sopenharmony_ci		mutex_unlock(&str_info->lock);
46662306a36Sopenharmony_ci		retval = -EBADRQC;
46762306a36Sopenharmony_ci		dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	return retval;
47162306a36Sopenharmony_ci}
472