xref: /openbmc/linux/sound/soc/intel/atom/sst/sst_stream.c (revision 9e3bd0f6)
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 #include "../../common/sst-dsp.h"
27 
28 int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
29 {
30 	struct snd_pcm_params *pcm_params;
31 	struct snd_sst_params *str_params;
32 	struct snd_sst_tstamp fw_tstamp;
33 	struct stream_info *str_info;
34 	int i, num_ch, str_id;
35 
36 	dev_dbg(sst_drv_ctx->dev, "Enter\n");
37 
38 	str_params = (struct snd_sst_params *)params;
39 	str_id = str_params->stream_id;
40 	str_info = get_stream_info(sst_drv_ctx, str_id);
41 	if (!str_info)
42 		return -EINVAL;
43 
44 	memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param));
45 	str_info->alloc_param.operation = str_params->ops;
46 	str_info->alloc_param.codec_type = str_params->codec;
47 	str_info->alloc_param.sg_count = str_params->aparams.sg_count;
48 	str_info->alloc_param.ring_buf_info[0].addr =
49 		str_params->aparams.ring_buf_info[0].addr;
50 	str_info->alloc_param.ring_buf_info[0].size =
51 		str_params->aparams.ring_buf_info[0].size;
52 	str_info->alloc_param.frag_size = str_params->aparams.frag_size;
53 
54 	memcpy(&str_info->alloc_param.codec_params, &str_params->sparams,
55 			sizeof(struct snd_sst_stream_params));
56 
57 	/*
58 	 * fill channel map params for multichannel support.
59 	 * Ideally channel map should be received from upper layers
60 	 * for multichannel support.
61 	 * Currently hardcoding as per FW reqm.
62 	 */
63 	num_ch = sst_get_num_channel(str_params);
64 	pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params;
65 	for (i = 0; i < 8; i++) {
66 		if (i < num_ch)
67 			pcm_params->channel_map[i] = i;
68 		else
69 			pcm_params->channel_map[i] = 0xff;
70 	}
71 
72 	sst_drv_ctx->streams[str_id].status = STREAM_INIT;
73 	sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT;
74 	sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type;
75 	sst_drv_ctx->streams[str_id].task_id = str_params->task;
76 	sst_drv_ctx->streams[str_id].num_ch = num_ch;
77 
78 	if (sst_drv_ctx->info.lpe_viewpt_rqd)
79 		str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start +
80 			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
81 	else
82 		str_info->alloc_param.ts = sst_drv_ctx->mailbox_add +
83 			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
84 
85 	dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
86 			str_info->alloc_param.ts);
87 	dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
88 			str_info->pipe_id, str_info->task_id);
89 
90 	return sst_realloc_stream(sst_drv_ctx, str_id);
91 }
92 
93 /**
94  * sst_realloc_stream - Send msg for (re-)allocating a stream using the
95  * @sst_drv_ctx  intel_sst_drv context pointer
96  * @str_id:	 stream ID
97  *
98  * Send a msg for (re-)allocating a stream using the parameters previously
99  * passed to sst_alloc_stream_mrfld() for the same stream ID.
100  * Return: 0 or negative errno value.
101  */
102 int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
103 {
104 	struct snd_sst_alloc_response *response;
105 	struct stream_info *str_info;
106 	void *data = NULL;
107 	int ret;
108 
109 	str_info = get_stream_info(sst_drv_ctx, str_id);
110 	if (!str_info)
111 		return -EINVAL;
112 
113 	dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
114 		str_id, str_info->pipe_id);
115 
116 	ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
117 			IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id,
118 			sizeof(str_info->alloc_param), &str_info->alloc_param,
119 			&data, true, true, false, true);
120 
121 	if (ret < 0) {
122 		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
123 		/* alloc failed, so reset the state to uninit */
124 		str_info->status = STREAM_UN_INIT;
125 		str_id = ret;
126 	} else if (data) {
127 		response = (struct snd_sst_alloc_response *)data;
128 		ret = response->str_type.result;
129 		if (!ret)
130 			goto out;
131 		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
132 		if (ret == SST_ERR_STREAM_IN_USE) {
133 			dev_err(sst_drv_ctx->dev,
134 				"FW not in clean state, send free for:%d\n", str_id);
135 			sst_free_stream(sst_drv_ctx, str_id);
136 		}
137 		str_id = -ret;
138 	}
139 out:
140 	kfree(data);
141 	return str_id;
142 }
143 
144 /**
145 * sst_start_stream - Send msg for a starting stream
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  * @str_id:	 stream ID
238  *
239  * This function is called by any function which wants to pause
240  * an already running stream.
241  */
242 int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
243 {
244 	int retval = 0;
245 	struct stream_info *str_info;
246 
247 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
248 	str_info = get_stream_info(sst_drv_ctx, str_id);
249 	if (!str_info)
250 		return -EINVAL;
251 	if (str_info->status == STREAM_PAUSED)
252 		return 0;
253 	if (str_info->status == STREAM_RUNNING ||
254 		str_info->status == STREAM_INIT) {
255 		if (str_info->prev == STREAM_UN_INIT)
256 			return -EBADRQC;
257 
258 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
259 				IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
260 				0, NULL, NULL, true, true, false, true);
261 
262 		if (retval == 0) {
263 			str_info->prev = str_info->status;
264 			str_info->status = STREAM_PAUSED;
265 		} else if (retval == -SST_ERR_INVALID_STREAM_ID) {
266 			retval = -EINVAL;
267 			mutex_lock(&sst_drv_ctx->sst_lock);
268 			sst_clean_stream(str_info);
269 			mutex_unlock(&sst_drv_ctx->sst_lock);
270 		}
271 	} else {
272 		retval = -EBADRQC;
273 		dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n");
274 	}
275 
276 	return retval;
277 }
278 
279 /**
280  * sst_resume_stream - Send msg for resuming stream
281  * @str_id:		stream ID
282  *
283  * This function is called by any function which wants to resume
284  * an already paused stream.
285  */
286 int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
287 {
288 	int retval = 0;
289 	struct stream_info *str_info;
290 
291 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
292 	str_info = get_stream_info(sst_drv_ctx, str_id);
293 	if (!str_info)
294 		return -EINVAL;
295 	if (str_info->status == STREAM_RUNNING)
296 		return 0;
297 
298 	if (str_info->resume_status == STREAM_PAUSED &&
299 	    str_info->resume_prev == STREAM_RUNNING) {
300 		/*
301 		 * Stream was running before suspend and re-created on resume,
302 		 * start it to get back to running state.
303 		 */
304 		dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n");
305 		str_info->status = STREAM_RUNNING;
306 		str_info->prev = STREAM_PAUSED;
307 		retval = sst_start_stream(sst_drv_ctx, str_id);
308 		str_info->resume_status = STREAM_UN_INIT;
309 	} else if (str_info->resume_status == STREAM_PAUSED &&
310 		   str_info->resume_prev == STREAM_INIT) {
311 		/*
312 		 * Stream was idle before suspend and re-created on resume,
313 		 * keep it as is.
314 		 */
315 		dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n");
316 		str_info->status = STREAM_INIT;
317 		str_info->prev = STREAM_PAUSED;
318 		str_info->resume_status = STREAM_UN_INIT;
319 	} else if (str_info->status == STREAM_PAUSED) {
320 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
321 				IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
322 				str_info->pipe_id, 0, NULL, NULL,
323 				true, true, false, true);
324 
325 		if (!retval) {
326 			if (str_info->prev == STREAM_RUNNING)
327 				str_info->status = STREAM_RUNNING;
328 			else
329 				str_info->status = STREAM_INIT;
330 			str_info->prev = STREAM_PAUSED;
331 		} else if (retval == -SST_ERR_INVALID_STREAM_ID) {
332 			retval = -EINVAL;
333 			mutex_lock(&sst_drv_ctx->sst_lock);
334 			sst_clean_stream(str_info);
335 			mutex_unlock(&sst_drv_ctx->sst_lock);
336 		}
337 	} else {
338 		retval = -EBADRQC;
339 		dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
340 	}
341 
342 	return retval;
343 }
344 
345 
346 /**
347  * sst_drop_stream - Send msg for stopping stream
348  * @str_id:		stream ID
349  *
350  * This function is called by any function which wants to stop
351  * a stream.
352  */
353 int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
354 {
355 	int retval = 0;
356 	struct stream_info *str_info;
357 
358 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
359 	str_info = get_stream_info(sst_drv_ctx, str_id);
360 	if (!str_info)
361 		return -EINVAL;
362 
363 	if (str_info->status != STREAM_UN_INIT) {
364 		str_info->prev = STREAM_UN_INIT;
365 		str_info->status = STREAM_INIT;
366 		str_info->cumm_bytes = 0;
367 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
368 				IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
369 				str_info->pipe_id, 0, NULL, NULL,
370 				true, true, true, false);
371 	} else {
372 		retval = -EBADRQC;
373 		dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
374 				str_info->status);
375 	}
376 	return retval;
377 }
378 
379 /**
380 * sst_drain_stream - Send msg for draining stream
381 * @str_id:		stream ID
382 *
383 * This function is called by any function which wants to drain
384 * a stream.
385 */
386 int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
387 			int str_id, bool partial_drain)
388 {
389 	int retval = 0;
390 	struct stream_info *str_info;
391 
392 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id);
393 	str_info = get_stream_info(sst_drv_ctx, str_id);
394 	if (!str_info)
395 		return -EINVAL;
396 	if (str_info->status != STREAM_RUNNING &&
397 		str_info->status != STREAM_INIT &&
398 		str_info->status != STREAM_PAUSED) {
399 			dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
400 				       str_info->status);
401 			return -EBADRQC;
402 	}
403 
404 	retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
405 			IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
406 			sizeof(u8), &partial_drain, NULL, true, true, false, false);
407 	/*
408 	 * with new non blocked drain implementation in core we dont need to
409 	 * wait for respsonse, and need to only invoke callback for drain
410 	 * complete
411 	 */
412 
413 	return retval;
414 }
415 
416 /**
417  * sst_free_stream - Frees a stream
418  * @str_id:		stream ID
419  *
420  * This function is called by any function which wants to free
421  * a stream.
422  */
423 int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
424 {
425 	int retval = 0;
426 	struct stream_info *str_info;
427 
428 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
429 
430 	mutex_lock(&sst_drv_ctx->sst_lock);
431 	if (sst_drv_ctx->sst_state == SST_RESET) {
432 		mutex_unlock(&sst_drv_ctx->sst_lock);
433 		return -ENODEV;
434 	}
435 	mutex_unlock(&sst_drv_ctx->sst_lock);
436 	str_info = get_stream_info(sst_drv_ctx, str_id);
437 	if (!str_info)
438 		return -EINVAL;
439 
440 	mutex_lock(&str_info->lock);
441 	if (str_info->status != STREAM_UN_INIT) {
442 		str_info->prev =  str_info->status;
443 		str_info->status = STREAM_UN_INIT;
444 		mutex_unlock(&str_info->lock);
445 
446 		dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
447 				str_id, str_info->pipe_id);
448 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
449 				IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
450 				NULL, NULL, true, true, false, true);
451 
452 		dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
453 				retval);
454 		mutex_lock(&sst_drv_ctx->sst_lock);
455 		sst_clean_stream(str_info);
456 		mutex_unlock(&sst_drv_ctx->sst_lock);
457 		dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
458 	} else {
459 		mutex_unlock(&str_info->lock);
460 		retval = -EBADRQC;
461 		dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
462 	}
463 
464 	return retval;
465 }
466